Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference

I have an Activity, which itself has three Fragments.

In one of these fragments, there is a RecyclerView with a custom adapter, and clicking on one of its items would go to another page, which is a new instance of the same Activity. However, a certain behaviour causes an error in my app.

From my Activity, clicking on one of the items brings up the new instance of the same Activity, which is fine. Then I press the back button and I am taken back to the first Activity. But clicking on one of these items again (to launch a new instance of the same Activity) causes the following error:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference

It is also important to consider that I am calling the new instance of the Activity (i.e. where the three items are), in one of the fragments I have in my Activity. So, when I am calling it, I have something like:

public class MyActivity extends AppCompatActivity {

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        ViewPager viewPager = (ViewPager) findViewById(R.id.detail_viewpager);
        viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));
        TabLayout tabLayout = (TabLayout) findViewById(R.id.detail_tabs);
        tabLayout.setTabTextColors(
                ContextCompat.getColor(this, R.color.text_white_secondary),
                ContextCompat.getColor(this, R.color.text_white));
        tabLayout.setSelectedTabIndicatorColor(ContextCompat.getColor(this, R.color.white));
        tabLayout.setupWithViewPager(viewPager);
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
    }

    ...

    public class ViewPagerAdapter extends FragmentPagerAdapter {

        public ViewPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return 3;
        }

        @Override
        public Fragment getItem(int position) {
            switch (position) {
                case 0: return new MainFragment();
                case 1: return new MyFragment();
                case 2: return new MyOtherFragment();
            }
            return null;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            Locale l = Locale.getDefault();
            switch (position) {
                case 0:
                    return getString(R.string.tab_main_frag).toUpperCase(l);
                case 1:
                    return getString(R.string.tab_my_frag).toUpperCase(l);
                case 2:
                    return getString(R.string.tab_my_other_frag).toUpperCase(l);
            }
            return null;
        }
    }

    ...

    public static class MyFragment extends Fragment implements MyRVAdapter.OnEntryClickListener {

        ...

        private ArrayList<ItemObj> mArrayList;

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            ...
            doStuff();
            ...
        }

        private void doStuff() {
            ...
            mArrayList = ...;
            MyRVAdapter adapter = new MyRVAdapter(getActivity(), mArrayList);
            adapter.setOnEntryClickListener(new MyRVAdapter.OnEntryClickListener() {
                @Override
                public void onEntryClick(View view, int position) {
                    Intent intent = new Intent(getActivity(), MyActivity.class);
                    intent.putExtra("INFORMATION", mArrayList.get(position));
                    startActivity(intent);
                }
            });
        }

        ...

    }

    ...
}

And here is part of my custom adapter:

public class MyRVAdapter extends RecyclerView.Adapter<MyRVAdapter.MyViewHolder> {

    public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        ...

        MyViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            ...
        }

        @Override
        public void onClick(View v) {
            // The user may not set a click listener for list items, in which case our listener
            // will be null, so we need to check for this
            if (mOnEntryClickListener != null) {
                mOnEntryClickListener.onEntryClick(v, getLayoutPosition());
            }
        }
    }

    private Context mContext;
    private ArrayList<ItemObj> mArray;

    public MyRVAdapter(Context context, ArrayList<ItemObj> array) {
        mContext = context;
        mArray = array;
    }

    @Override
    public int getItemCount() {
        return mArray.size();
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.tile_simple, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        ItemObj anItem = mArray.get(position);

        ...
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
    }


    private static OnEntryClickListener mOnEntryClickListener;

    public interface OnEntryClickListener {
        void onEntryClick(View view, int position);
    }

    public void setOnEntryClickListener(OnEntryClickListener onEntryClickListener) {
        mOnEntryClickListener = onEntryClickListener;
    }

}

Here is the error in full:

01-23 14:07:59.083 388-388/com.mycompany.myapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mycompany.myapp, PID: 388
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
    at android.content.ComponentName.<init>(ComponentName.java:77)
    at android.content.Intent.<init>(Intent.java:4570)
    at com.mycompany.myapp.MyActivity$MyFragment$1.onEntryClick(MyActivity.java:783)
    at com.mycompany.myapp.adapter.MyRVAdapter$MyViewHolder.onClick(MyRVAdapter.java:42)
    at android.view.View.performClick(View.java:5197)
    at android.view.View$PerformClick.run(View.java:20926)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:145)
    at android.app.ActivityThread.main(ActivityThread.java:5951)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)

The error points to the first line: Intent intent = new Intent(getActivity(), MyActivity.class); (from the fragment) first, with line after (in the error) pointing to mOnEntryClickListener.onEntryClick(v, getLayoutPosition()); from the overriden onClick method in the custom adapter.

I have also read similar answers, but they have not solved my issue.

Edit:

By using:

if (getActivity() == null) {
    Log.d(LOG_TAG, "Activity context is null");
} else {
    Intent intent = new Intent(getActivity(), MyActivity.class);
    intent.putExtra("INFORMATION", mArrayList.get(position));
    startActivity(intent);
}

in the inner class (onEntryClick) in the fragment, I found that calling getActivity() returns null.

like image 677
Farbod Salamat-Zadeh Avatar asked Jan 19 '16 21:01

Farbod Salamat-Zadeh


1 Answers

So, the issue is this line

private static OnEntryClickListener mOnEntryClickListener;

Since it is static you have a single instance of the class at runtime. When you click on an item, a second instance of the same Activity is created, and another instance of mOnEntryClickListener is created too, overwriting the previous one. So, when you press back to return to the first instance of the Activity, you are using the instance of mOnEntryClickListener of the second Activity, that has been destroyed.

like image 167
Mimmo Grottoli Avatar answered Nov 16 '22 01:11

Mimmo Grottoli