我为此感到茫然。我在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;
}
}
如果我在标签之间滚动,我将它们添加到堆栈('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)
[编辑]我忘了提及我覆盖FragmentPagerAdapter.getPageTitle()并且它永远不会返回null(默认情况下转到字符串)。
答案 0 :(得分:4)
最后!我现在能够可靠地重新创建此错误!
我发现重新创建错误的另一种方法是关闭活动/应用,并使用ViewPager片段快速重新打开页面。您可能需要尝试几次,因为在我的测试中,我必须在大约30ms内重新打开应用程序。对于不同的速度设备,此时间可能更慢或更快。
问题是我只显式创建了Fragment(使用new
)一次,并保留了对该实例的引用,以便我可以重用它。解决此问题的一个简单方法是始终返回new
片段的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();
}
}
}
ps - 根问题可能与Fragment生命周期有关,并且在它被销毁时再次尝试使用它。
pps - 此解决方案修复了android.app.Fragment.setUserVisibleHint(Fragment.java:997)
的NullPointerException,也适用于android.support.v4.app.Fragment.setUserVisibleHint
。
答案 1 :(得分:1)
对我来说这是一个真正的大脑扭转者。我们删除了替换Fragment
的所有代码,并在Activity
的整个生命周期中保留了相同的片段,但仍然存在此问题。直到我们viewPager.setOffscreenPageLimit(TABS);
TABS
的标签数量(在我们的例子中为4),我们才停止获取引用的NullPointerException
。
FWIW - 我很确定问题出在谷歌的代码中。我们无法在运行Lollipop的Nexus 5上失败,但在运行Kitkat的三星设备上失败了。当我跟踪错误本身时,看起来失败的原因是被引用的Fragment
已经通过内部Fragment.initState
函数,因为Fragment
的{{1}}是-1
答案 2 :(得分:0)
即使我使用了FragmentStatePagerAdapter,我的情况非常相似(Fragment.setUserVisibleHint
中的异常也是如此)。当底层数据发生变化时,我的应用程序会出现随机(因此难以重现)崩溃。
在我的情况下,我终于通过覆盖适配器中的以下方法来摆脱这种崩溃:
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
// don't super !
}
我认为这个类中存在一个错误,因为StackOverflow中的问题数量与此类似。
我希望这对某人有用。
编辑:我在android.support.v4.app.Fragment.setUserVisibleHint null pointer on app resuming上发布了类似的答案,但我并不确定这些问题是否重复。但是,我认为这个答案可以帮助一些人找到类似症状。我该怎么说呢?