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

37,601

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.

Share:
37,601
Farbod Salamat-Zadeh
Author by

Farbod Salamat-Zadeh

Updated on July 09, 2022

Comments

  • Farbod Salamat-Zadeh
    Farbod Salamat-Zadeh almost 2 years

    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.

  • Farbod Salamat-Zadeh
    Farbod Salamat-Zadeh over 8 years
    Thanks for the answer. To be honest, for me right now it's almost midnight, so I'll get some sleep and test it out tomorrow. ;)
  • Farbod Salamat-Zadeh
    Farbod Salamat-Zadeh over 8 years
    Your solution didn't work for me. However, I mentioned in my answer that I have buttons which, when clicked, open the Activity. But I'm actually using a RecyclerView with a custom adapter I made, and the Activity is opened when I click on an item from that. The issue may be in the adapter because when I tested something what I had before with three buttons instead of the RecyclerView and adapter, it worked fine. The reason I didn't mention it before is that I assumed there would not be an issue with the adapter, so not including it would have made a simpler question.
  • Farbod Salamat-Zadeh
    Farbod Salamat-Zadeh over 8 years
    I've updated my answer, I'm not sure if it helps, but I thought I might as well include the custom adapter if the problem is there.
  • Cory Charlton
    Cory Charlton over 8 years
    The problem likely is, sort of, there. Where do you set your OnEntryClickListener?
  • Farbod Salamat-Zadeh
    Farbod Salamat-Zadeh over 8 years
    Sorry - see my updated answer (I forgot to include it previously).
  • Cory Charlton
    Cory Charlton over 8 years
    Ok so then I assume that when you said "Your solution didn't work for me." that means that you tried to implement OnEntryClickListener on the fragment and replaced the anonymous method with this in your adapter.setOnEntryClickListener() in `doStuff()?
  • Cory Charlton
    Cory Charlton over 8 years
    Ok I provided a hack that might work as I've got nothing at this point :)
  • Farbod Salamat-Zadeh
    Farbod Salamat-Zadeh over 8 years
    That solved that particular error, but resulted in a different one: java.lang.IllegalStateException: Fragment MyFragment{18a42f07} not attached to Activity.
  • Cory Charlton
    Cory Charlton over 8 years
  • Farbod Salamat-Zadeh
    Farbod Salamat-Zadeh over 8 years
    I can't reference openAnotherActivity (non-static context) from a static context. Also, is MyApplication.getInstance() meant to be from the other answer.
  • ThaiPD
    ThaiPD over 8 years
    So I think the problem is the static context. Why do you need to make the Holder as the static class while it can be in a normal context
  • Farbod Salamat-Zadeh
    Farbod Salamat-Zadeh over 8 years
    Thank you so much! This solved my problem, but I also had to remove static from my ViewHolder as well. I also read up on this particular issue of static inner classes, and found a great answer about memory leaks and static/inner classes.
  • Zhu
    Zhu almost 6 years
    can you please help me to fix this error stackoverflow.com/questions/51405397/… @MimmoGrottoli
  • David Wasser
    David Wasser almost 6 years
    @FarbodSalamat-Zadeh actually there is no reason that you would need to remove static from your Viewholder declaration. A Viewholder should be a static class, ie: just a data container with no behaviour (methods). If you are adding methods to a Viewholder that force you to remove the static modifier from the class definition, it means that each and every Viewholder object now has a reference to the outer class (in this case, the adapter). This is a waste of storage and means that your architecture is flawed. Just sayin'