使用ViewPager时,Fragment.setUserVisibleHint()中的NPE

Mar*_*her 10 android android-fragments

我为此感到茫然.我在ViewPager中手动切换标签.我在Activity中有这个代码:

@Override
public void onBackPressed()
{
    if (childFragmentStack.empty())
    {
        // Go to the devices screen
        Intent intent = new Intent(this, SelectDeviceActivity.class);
        startActivity(intent);
    }
    else
    {
        Fragment fragment = childFragmentStack.pop();

        if (fragment == null)
        {
            return;
        }

        processingBackStack = true;

        if (fragment instanceof ViewChildFragment)
        {
            viewFragment.activateFragment((ViewChildFragment) fragment);
            mViewPager.setCurrentItem(VIEW_FRAGMENT_INDEX, true);
        }
        else if (fragment instanceof SetupChildFragment)
        {
            setupFragment.activateFragment((SetupChildFragment) fragment);
            mViewPager.setCurrentItem(SETUP_FRAGMENT_INDEX, true); //**
        }
        else if (fragment == homeFragment)
        {
            mViewPager.setCurrentItem(HOME_FRAGMENT_INDEX, true); //**
        }

        processingBackStack = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我在选项卡之间滚动,我将它们添加到堆栈('childFragmentStack').我正在使用FragmentPagerAdapter来处理片段.如果我执行View-> Setup-> View-> Setup之类的操作然后将其反转,它只会达到Setup-> View-> CRASH.这就像当我按回设置碎片不再对我正在做的事情有效,但它永远不会重新创建!安装程序片段仅在MainActivity.onCreate()中创建,因此它应该仍然存在且有效.

NPE发生在我标记为**的行上.这是完整的堆栈跟踪:

    04-18 16:04:57.096: E/AndroidRuntime(13072): FATAL EXCEPTION: main
    04-18 16:04:57.096: E/AndroidRuntime(13072): java.lang.NullPointerException
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.support.v4.app.Fragment.setUserVisibleHint(Fragment.java:841)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.support.v4.app.FragmentPagerAdapter.setPrimaryItem(FragmentPagerAdapter.java:130)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.support.v4.view.ViewPager.populate(ViewPager.java:1066)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:550)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:509)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:501)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at com.lochinvar.serf.MainActivity.onBackPressed(MainActivity.java:234)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.app.Activity.onKeyUp(Activity.java:2131)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.view.KeyEvent.dispatch(KeyEvent.java:2633)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.app.Activity.dispatchKeyEvent(Activity.java:2361)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1819)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.view.ViewRootImpl.deliverKeyEventPostIme(ViewRootImpl.java:3577)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.view.ViewRootImpl.handleImeFinishedEvent(ViewRootImpl.java:3547)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:2797)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.os.Handler.dispatchMessage(Handler.java:99)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.os.Looper.loop(Looper.java:137)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at android.app.ActivityThread.main(ActivityThread.java:4745)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at java.lang.reflect.Method.invokeNative(Native Method)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at java.lang.reflect.Method.invoke(Method.java:511)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
    04-18 16:04:57.096: E/AndroidRuntime(13072):    at dalvik.system.NativeStart.main(Native Method)
Run Code Online (Sandbox Code Playgroud)

[编辑]我忘了提到我覆盖FragmentPagerAdapter.getPageTitle()并且它永远不会返回null(默认情况下转到字符串).

Ano*_*age 4

最后!我现在能够可靠地重现此错误!

我发现重新创建错误的另一种方法是关闭活动/应用程序,然后使用 ViewPager 片段快速重新打开页面。您可能需要尝试几次,因为在我的测试中,我必须在大约 30 毫秒内重新打开应用程序。对于不同速度的设备,这个时间可能会更慢或更快。

问题是我只显式创建了 Fragment (使用new)一次,并保留了对该实例的引用,以便我可以重用它。解决此问题的一个简单方法是始终返回newFragment 的实例FragmentPagerAdapter.getItem(...),如下所示。

public class ViewPagerAdapter extends FragmentPagerAdapter {
    ...

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0: return mMyFragment; // Error. Has the edge-case crash.
            case 1: return new MyFragment(); // Works.
            default: return new MyDefaultFragment();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

ps - 根本问题可能与片段生命周期以及在其被销毁时尝试再次使用它有关。

pps - 此解决方案修复了 NullPointerException,android.app.Fragment.setUserVisibleHint(Fragment.java:997)并且也适用于android.support.v4.app.Fragment.setUserVisibleHint.