尝试在空对象引用上调用虚拟方法“java.lang.String android.content.Context.getPackageName()”
Posted
技术标签:
【中文标题】尝试在空对象引用上调用虚拟方法“java.lang.String android.content.Context.getPackageName()”【英文标题】:Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference 【发布时间】:2016-04-25 13:09:56 【问题描述】:我有一个Activity
,它本身有三个Fragment
s。
在其中一个片段中,有一个带有自定义适配器的RecyclerView
,单击其中一个项目将转到另一个页面,这是相同Activity
的新实例。但是,某种行为会导致我的应用出现错误。
在我的 Activity 中,单击其中一项会显示同一 Activity 的新实例,这很好。然后我按下后退按钮,我被带回到第一个活动。但是再次单击这些项目之一(以启动同一 Activity 的新实例)会导致以下错误:
java.lang.NullPointerException:
考虑到我在我的 Activity 中的一个片段中调用 Activity 的新实例(即三个项目所在的位置)也很重要。所以,当我调用它时,我有类似的东西:
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);
);
...
...
这是我的自定义适配器的一部分:
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;
这是完整的错误:
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)
错误指向第一行:Intent intent = new Intent(getActivity(), MyActivity.class);
(来自片段)首先,后面的行(错误中)指向自定义适配器中覆盖的onClick
方法中的mOnEntryClickListener.onEntryClick(v, getLayoutPosition());
。
我也读过类似的答案,但他们没有解决我的问题。
编辑:
通过使用:
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);
在片段的内部类(onEntryClick
)中,我发现调用getActivity()
会返回null
。
【问题讨论】:
getActivity()
可能返回 null。你在哪里设置你的OnClickListener
?
请添加 java 代码 - 没必要 - 问题出在代码中
这听起来就像你在使用同一个 Fragment,但是使用了一个新的 Activity,所以当它去获取 Activity 引用时,它不再存在了。您是在使用保留的 Fragment,还是将 Fragment 引用传递给 Activity 的新实例?我们可能需要查看一些代码才能理解这一点。
我认为它发生的是OnClickListener
正在封装原始片段。没有看到OnClickListener
的设置位置,虽然我不能确定。
@CoryCharlton OnClickListener
在我的Activity
中的Fragment
中被调用。
【参考方案1】:
即使问题已经解决了,我也想说我的问题是什么,我的解决方案。
问题
在我的代码中,我添加了一个带有firebaseAuth.addAuthStateListener(listener)
的侦听器,因此当用户登录并启动新活动时,listener
被执行并导致错误(因为在里面我有另一个startActivity(getContext(), ...)
)。
解决方案
使用方法firebaseAuth.removeAuthStateListener(listener)
传递侦听器的引用并解决问题。在开始导致问题的活动之前,您必须删除引用。
【讨论】:
【参考方案2】:在您的片段中创建您的活动类型的变量:
public MainActivity activity;
然后使用attach上的方法并赋值:
@Override
public void onAttach(Activity activity)
this.activity = activity;
然后将您的意图与活动一起用作上下文:
Intent mIntent = new Intent(activity, MyActivity.class);
【讨论】:
【参考方案3】:所以,问题是这一行
private static OnEntryClickListener mOnEntryClickListener;
由于它是静态的,因此您在运行时拥有该类的单个实例。当您单击一个项目时,会创建同一个 Activity 的第二个实例,并且还会创建另一个 mOnEntryClickListener
实例,覆盖前一个实例。因此,当您按下返回以返回 Activity 的第一个实例时,您正在使用第二个 Activity 的 mOnEntryClickListener
实例,该实例已被销毁。
【讨论】:
非常感谢!这解决了我的问题,但我也必须从我的ViewHolder
中删除static
。我还阅读了这个关于静态内部类的特殊问题,并找到了 a great answer 关于内存泄漏和静态/内部类的信息。
你能帮我解决这个错误吗***.com/questions/51405397/…@MimmoGrottoli
@FarbodSalamat-Zadeh 实际上没有理由需要从 Viewholder
声明中删除 static
。 Viewholder
应该是 static class
,即:只是一个没有行为(方法)的数据容器。如果您向Viewholder
添加方法,迫使您从class
定义中删除static
修饰符,这意味着每个Viewholder
对象现在都有对外部类的引用(在这种情况下,适配器)。这是对存储的浪费,意味着您的架构存在缺陷。只是说'【参考方案4】:
在您的片段的 oncreate 中,保存您的活动的引用,并在启动其他活动之前检查您的活动是否处于恢复状态。
public static class MyFragment extends Fragment implements MyRVAdapter.OnEntryClickListener
...
private ArrayList<ItemObj> mArrayList;
private MyActivity mActivity;
@Override
public void onCreate(Bundle savedInstanceState)
mActivity = getActivity();
@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)
if (!mActivity.isFinishing()
Intent intent = new Intent(mActivity, MyActivity.class);
intent.putExtra("INFORMATION", mArrayList.get(position));
startActivity(intent);
);
...
【讨论】:
【参考方案5】:尝试使用我的解决方案: 在您的 MyActivity 中,创建一个新函数:
public void openAnotherActivity(ObjectItem item)
Intent intent = new Intent(MyApplication.getInstance(), MyActivity.class);
intent.putExtra("INFORMATION", item);
startActivity(intent);
然后修改doStuff()为:
private void doStuff()
...
mArrayList = ...;
MyRVAdapter adapter = new MyRVAdapter(getActivity(), mArrayList);
adapter.setOnEntryClickListener(new MyRVAdapter.OnEntryClickListener()
@Override
public void onEntryClick(View view, int position)
openAnotherActivity(mArrayList.get(position))
);
我不确定它是否能帮助你,但我认为至少它可以解决context
问题
【讨论】:
我无法从静态上下文中引用openAnotherActivity
(非静态上下文)。另外,MyApplication.getInstance()
是否意味着来自另一个答案。
所以我认为问题在于静态上下文。为什么需要将Holder设置为静态类,而它可以在正常上下文中【参考方案6】:
问题可能与您的匿名OnClickListener
从原始片段中捕获getActivity()
方法有关。您可以尝试在您的MyFragment
上实现OnClickListener
,看看行为是否发生了变化(可能没那么简单):
public static class MyFragment extends Fragment implements View.OnClickListener
...
private void doStuff()
button.setOnClickListener(this);
@Override
public void onClick(View v)
Intent intent = new Intent(getActivity(), MyActivity.class);
intent.putExtra("INFORMATION", value);
startActivity(intent);
...
编辑:这是一种技巧,我通常不会推荐,但如果您遇到困难,可能会解决问题...
扩展Application
以提供静态应用程序实例:
public class MyApplication extends Application
private static MyApplication _instance;
@Override
public void onCreate()
super.onCreate();
_instance = this;
public static MyApplication getInstance()
return _instance;
修改您的 AndroidManifest.xml 以便您的应用程序运行 MyApplication
:
<application
android:name="com.package.MyApplication"
<!-- Rest of your manifest -->
然后将getActivity()
替换为对MyApplication.getInstance()
的调用:
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(MyApplication.getInstance(), MyActivity.class);
intent.putExtra("INFORMATION", mArrayList.get(position));
startActivity(intent);
);
【讨论】:
感谢您的回答。老实说,对我来说现在已经快午夜了,所以我会睡一觉,明天再测试一下。 ;) 您的解决方案对我不起作用。但是,我在回答中提到我有按钮,单击时会打开活动。但我实际上是在使用RecyclerView
和我制作的自定义适配器,当我点击其中的一个项目时,活动就会打开。问题可能出在适配器中,因为当我使用三个按钮而不是 RecyclerView 和适配器测试我之前拥有的东西时,它运行良好。我之前没有提到它的原因是我认为适配器不会有问题,所以不包括它会提出一个更简单的问题。
我已经更新了我的答案,我不确定它是否有帮助,但我想如果问题存在,我还不如包含自定义适配器。
问题可能就在那里。你在哪里设置你的OnEntryClickListener
?
抱歉 - 请参阅我的更新答案(我之前忘记包含它)。以上是关于尝试在空对象引用上调用虚拟方法“java.lang.String android.content.Context.getPackageName()”的主要内容,如果未能解决你的问题,请参考以下文章
java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法“ActionBar.setNavigationMode(int)”
NullPointerException:尝试在空对象引用上调用虚拟方法 AlertDialog.setTitle(java.lang.CharSequence) [重复]
(Kotlin,viewBinding)java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法“boolean java.lang.Thread.isAlive(
尝试在空对象引用上调用虚拟方法“java.lang.String android.content.Context.getPackageName()”
尝试在空对象引用上调用虚拟方法“java.lang.String android.content.Context.getPackageName()”
java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法“int android.view.View.getImportantForAccessibility()”