1

我的应用程序在 MainActivity 中包含带有两个片段的 ViewPager。第一个片段包含 ListView。我从来没有看到过这个,但我在 Google Play 中看到了用户关于 RuntimeException 的报告:

java.lang.RuntimeException: Unable to resume activity {com.my.project/com.my.project.MainActivity}: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { (has extras) }} to activity {com.my.project/com.my.project.MainActivity}: java.lang.NullPointerException
 at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2120)
 at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2135)
 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1668)
 at android.app.ActivityThread.access$1500(ActivityThread.java:117)
 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
 at android.os.Handler.dispatchMessage(Handler.java:99)
 at android.os.Looper.loop(Looper.java:130)
 at android.app.ActivityThread.main(ActivityThread.java:3683)
 at java.lang.reflect.Method.invokeNative(Native Method)
 at java.lang.reflect.Method.invoke(Method.java:507)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:875)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:633)
 at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { (has extras) }} to activity {com.my.project/com.my.project.MainActivity}: java.lang.NullPointerException
 at android.app.ActivityThread.deliverResults(ActivityThread.java:2532)
 at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2107)
 ... 12 more
Caused by: java.lang.NullPointerException
 at com.my.project.FirstFragment.load(FirstFragment.java:551)
 at com.my.project.MainActivity.onActivityResult(MainActivity.java:132)
 at android.app.Activity.dispatchActivityResult(Activity.java:3908)
 at android.app.ActivityThread.deliverResults(ActivityThread.java:2528)
 ... 13 more

这是来自 FirstFragment.java 的代码:

public class FirstFragment extends Fragment {

    ArrayList<ListItemObject> listItems = null;
    ArrayAdapter<ListItemObject> mAdapter;

    void load() {
            mAdapter.clear(); // I get error here, that is FirstFragment.java:551
            ...
    }

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

        listItems = new ArrayList<ListItemObject>();
        mAdapter = new MyAdapter(getActivity(), listItems);
        listView.setAdapter(mAdapter);
    }

}

这就是 mAdapter 的所有出现。而且我无法理解,它如何导致 NullPointerException。我认为有时 Fragment1 会破坏和重新创建,但没有 onCreateView()。我与一位遇到此问题的用户交谈,他说我在设置中取消选中“开发人员选项”中的“不保留活动”后,此错误就会消失。不知道,能修吗?或者我需要说我的所有用户“取消选中此选项”?

在我的 NainActivity 中:

public class MainActivity extends FragmentActivity {

    Vector<Fragment> fragments;
    ViewPager viewPager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        viewPager = (ViewPager) findViewById(R.id.pager);

        fragments = new Vector<Fragment>();
        fragments.add(Fragment.instantiate(this, Fragment1.class.getName()));
        fragments.add(Fragment.instantiate(this, Fragment2.class.getName()));

        viewPager.setOffscreenPageLimit(fragments.size());
        PagerAdapter pagerAdapter = new PagerAdapter(super.getSupportFragmentManager(), fragments);

        viewPager.setAdapter(pagerAdapter);

        viewPager.setCurrentItem(0);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode==1) {
            ((MainChat)fragments.get(0)).load();
        }
    }

    class PagerAdapter extends FragmentPagerAdapter implements IconPagerAdapter {

        private List<Fragment> fragments;

        public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
            super(fm);
            this.fragments = fragments;
        }

        @Override
        public Fragment getItem(int position) {
            return this.fragments.get(position);
        }

        @Override
        public int getCount() {
            return this.fragments.size();
        }

    }

}
4

2 回答 2

0

正在发生的事情是包含片段的活动已被处理掉。这可能在活动未显示的任何时候发生 - 您的用户所做的是更改开发人员设置,该设置会积极破坏活动以允许您查看类似这样的编码问题。问题仍然可能发生,并且设备可用的资源越少(因为它的内存很小,或者因为很多其他的东西正在运行),Android 这样做的频率就越高。

在解释了潜在问题的背景之后,让我们继续讨论onActivityResult()代码中的特定问题。此方法在视图生命周期中的某个点被调用,在您的片段和活动周围的上下文被重构之前,因此您不能在此方法中对您的片段进行任何有意义的工作,并确保它始终有效。而是将响应保存在类级别变量中并使用它,onResume()无论活动是否被破坏,都将在其中调用它。

顺便说一句,您应该将该方法移动到片段中 - 并且始终在您自己的代码之前onActivityResult()调用。super.onActivityResult()

最后请注意,Android 会随心所欲地销毁和重新创建片段(例如,当您旋转设备时,所有片段都会被销毁并重新创建)。因此,您应该确保您了解并使用 Activity 和 Fragment 生命周期,而不是像 Alex 的解决方案所建议的那样反对它们。这只会导致其他难以诊断的问题。

于 2013-04-28T16:44:29.590 回答
0

我认为错误的原因是您的 MainActivity 被破坏,然后被 Android OS 重新创建。

这意味着将在您的 MainActivity.onCreate() 方法中再次创建片段列表,但 PagerAdapter 不会使用这些片段,而是使用 FragmentManager 为您恢复的片段实例(例如,不会调用 PagerAdapter.getItem() )。并且由于未使用片段列表中的 FirstFragment 实例,它不会收到对 FirstFragment.onCreateView() 的调用,并且 mAdapter 实例仍将为空,那么您将调用 FirstFragment.load() 方法。

解决此问题的最简单(但不是很好)的方法是通过在 MainActivity.onCreate() 中将 null 作为 savedInstanceState 参数传递来抑制片段的恢复:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(null);
    ...
}

另一种方法是按需在 PagerAdapter 中创建片段:

@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0: return Fragment.instantiate(this, Fragment1.class.getName());
        case 1: return Fragment.instantiate(this, Fragment2.class.getName());
        default: throw new RuntimException();
    }
}

并以这种方式存储片段实例:

@Override
public Object instantiateItem(View container, int position) {
    Fragment fr = (Fragment) super.instantiateItem(container, position);
    fragments[position] = fr;
    return fr;
}

(注:第二种方式我没有测试过,所以可能行不通)

顺便说一句,您可以在 Android 4.0 设置中选中“不保留活动”开发人员选项来测试此类问题。

于 2012-12-25T05:46:15.767 回答