3

我有一个Activity,它本身有三个Fragment s。尝试在空对象引用上调用虚拟方法'java.lang.String android.content.Context.getPackageName()'

在其中一个片段中,有一个RecyclerView带有自定义适配器,并且单击其中一个项目将转到另一个页面,该页面是相同Activity的新实例。但是,某些行为会在我的应用程序中导致错误。

从我的活动中,点击其中一个项目可以调出相同Activity的新实例,这很好。然后我按下后退按钮,然后回到第一个活动。但是,再次点击这些项目之一(启动同一活动的新实例)导致以下错误:

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

同样重要的是要考虑到我打电话了活动的新实例(即其中这三个项目是),我在我的活动中的一个片段。所以,当我打电话吧,我有这样的:

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);(来自片段)首先,线后(在错误中)指向mOnEntryClickListener.onEntryClick(v, getLayoutPosition());来自自定义适配器中的覆盖onClick方法河

我也读过类似的答案,但他们还没有解决我的问题。

编辑:

通过使用:

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

+2

'getActivity()'可能返回null。你在哪里设置你的'OnClickListener'? –

+0

请添加java代码并且 - 没必要 - 问题出现在代码中 – piotrek1543

+0

它几乎听起来像您使用的是相同的Fragment,但带有一个新的Activity,因此当它获取Activity引用时,它不再存在。你是否在使用保留的片段,或者你是否将片段引用传递给活动的新实例?我们可能需要查看一些代码才能了解这一点。 – NoChinDeluxe

回答

8

所以,问题是这条线

private static OnEntryClickListener mOnEntryClickListener; 

由于它是静态的,你在运行时拥有类的一个实例。当您单击某个项目时,会创建同一活动的第二个实例,并创建另一个实例mOnEntryClickListener,覆盖前一个实例。因此,当您按回以返回到活动的第一个实例时,您正在使用第二个活动的mOnEntryClickListener实例,该实例已被销毁。

+0

非常感谢!这解决了我的问题,但我也必须从'ViewHolder'中删除'static'。我也读了关于静态内部类的这个特定问题,并且发现了关于内存泄漏和静态/内部类的[很好的答案](http://stackoverflow.com/a/10968689/4230345)。 –

0

该问题很可能与您的匿名OnClickListener从原始片段捕获getActivity()方法有关。你可以尝试实现您MyFragmentOnClickListener,看看行为在所有的变化(可能不是那么简单):

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); 
     } 
    }); 
} 
+0

感谢您的答复。说实话,现在对我来说已经快到午夜了,所以我明天会睡一觉并测试一下。 ;) –

+0

你的解决方案并不适合我。不过,我在我的回答中提到,我有按钮,点击后可打开活动。但是我实际上使用了一个带有自定义适配器的'RecyclerView',并且当我点击一个项目时打开Activity。这个问题可能出现在适配器中,因为当我使用三个按钮而不是RecyclerView和适配器测试了以前的东西时,它工作正常。之前我没有提到它的原因是我认为适配器不存在问题,所以不包括它会产生一个更简单的问题。 –

+0

我已经更新了我的答案,我不确定它是否有帮助,但是我认为如果问题存在,我可能还会包含自定义适配器。 –

0

尝试使用我的解决方案: 在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

+0

我无法从静态上下文中引用'openAnotherActivity'(非静态上下文)。另外,'MyApplication.getInstance()'意味着来自其他答案。 –

+0

所以我认为问题是静态的上下文。为什么你需要将Holder作为静态类,而它可以在正常情况下 –

0

在你片段的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); 
       } 
      } 
     }); 
    } 

    ... 

} 
相关问题