在开发人员控制台错误报告中,有时我会看到带有 NPE 问题的报告。我不明白我的代码有什么问题。在模拟器上,我的设备应用程序在没有强制关闭的情况下运行良好,但是当调用 getActivity() 方法时,一些用户在片段类中得到 NullPointerException。
活动
pulic class MyActivity extends FragmentActivity{ private ViewPager pager; private TitlePageIndicator indicator; private TabsAdapter adapter; @Override public void onCreate(Bundle savedInstanceState) { pager = (ViewPager) findViewById(R.id.pager); indicator = (TitlePageIndicator) findViewById(R.id.indicator); adapter = new TabsAdapter(getSupportFragmentManager(), false); adapter.addFragment(new FirstFragment()); adapter.addFragment(new SecondFragment()); indicator.notifyDataSetChanged(); adapter.notifyDataSetChanged(); // push first task FirstTask firstTask = new FirstTask(MyActivity.this); // set first fragment as listener firstTask.setTaskListener((TaskListener) adapter.getItem(0)); firstTask.execute(); } indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageSelected(int position) { Fragment currentFragment = adapter.getItem(position); ((Taskable) currentFragment).executeTask(); } @Override public void onPageScrolled(int i, float v, int i1) {} @Override public void onPageScrollStateChanged(int i) {} }); }
异步任务类
public class FirstTask extends AsyncTask{ private TaskListener taskListener; ... @Override protected void onPostExecute(T result) { ... taskListener.onTaskComplete(result); } }
片段类
public class FirstFragment extends Fragment immplements Taskable, TaskListener{ public FirstFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.first_view, container, false); } @Override public void executeTask() { FirstTask firstTask = new FirstTask(MyActivity.this); firstTask.setTaskListener(this); firstTask.execute(); } @Override public void onTaskComplete(T result) { // NPE is here Resources res = getActivity().getResources(); ... } }
当应用程序从后台恢复时,可能会发生此错误。在这种情况下,我应该如何正确处理这种情况?
这是我的例子:
pulic class MyActivity extends FragmentActivity{ private ViewPager pager; private TitlePageIndicator indicator; private TabsAdapter adapter; private Bundle savedInstanceState; @Override public void onCreate(Bundle savedInstanceState) { .... this.savedInstanceState = savedInstanceState; pager = (ViewPager) findViewById(R.id.pager);; indicator = (TitlePageIndicator) findViewById(R.id.indicator); adapter = new TabsAdapter(getSupportFragmentManager(), false); if (savedInstanceState == null){ adapter.addFragment(new FirstFragment()); adapter.addFragment(new SecondFragment()); }else{ Integer count = savedInstanceState.getInt("tabsCount"); String[] titles = savedInstanceState.getStringArray("titles"); for (int i = 0; i < count; i++){ adapter.addFragment(getFragment(i), titles[i]); } } indicator.notifyDataSetChanged(); adapter.notifyDataSetChanged(); // push first task FirstTask firstTask = new FirstTask(MyActivity.this); // set first fragment as listener firstTask.setTaskListener((TaskListener) getFragment(0)); firstTask.execute(); } private Fragment getFragment(int position){ return savedInstanceState == null ? adapter.getItem(position) : getSupportFragmentManager().findFragmentByTag(getFragmentTag(position)); } private String getFragmentTag(int position) { return "android:switcher:" + R.id.pager + ":" + position; } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("tabsCount", adapter.getCount()); outState.putStringArray("titles", adapter.getTitles().toArray(new String[0])); } indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageSelected(int position) { Fragment currentFragment = adapter.getItem(position); ((Taskable) currentFragment).executeTask(); } @Override public void onPageScrolled(int i, float v, int i1) {} @Override public void onPageScrollStateChanged(int i) {} });
这段代码的主要思想是,在正常运行应用程序时,您会创建新的片段并将它们传递给适配器。当您恢复应用程序片段管理器时,您已经拥有该片段的实例,您需要从片段管理器获取它并将其传递给适配器。
更新
此外,在调用 getActivity() 之前使用片段检查 isAdded 是一个很好的做法。当片段与活动分离时,这有助于避免空指针异常。例如,一个活动可能包含一个推送异步任务的片段。任务完成后,将调用 onTaskComplete 侦听器。
@Override public void onTaskComplete(List<Feed> result) { progress.setVisibility(View.GONE); progress.setIndeterminate(false); list.setVisibility(View.VISIBLE); if (isAdded()) { adapter = new FeedAdapter(getActivity(), R.layout.feed_item, result); list.setAdapter(adapter); adapter.notifyDataSetChanged(); } }
如果我们打开fragment,推送一个任务,然后快速按回返回上一个activity,当任务完成后,它会通过调用getActivity()方法尝试访问onPostExecute()中的activity。如果活动已经分离并且此检查不存在:
if (isAdded())
然后应用程序崩溃。