使用 Fragments 和 ViewPager 一段时间后,Android 应用程序崩溃

Posted

技术标签:

【中文标题】使用 Fragments 和 ViewPager 一段时间后,Android 应用程序崩溃【英文标题】:Android app crashing after a while using Fragments and ViewPager 【发布时间】:2012-06-21 06:19:32 【问题描述】:

在尝试恢复我的片段时,我的 android 应用程序崩溃了。我没有将任何自定义变量添加到我要恢复的包中,这都是默认的。我正在使用片段和 ViewPager。请参阅下面的代码 sn-ps:

public static class MyAdapter extends FragmentStatePagerAdapter 
    public MyAdapter(FragmentManager fm) 
        super(fm);
    

    @Override
    public int getCount() 
        return NUM_ITEMS;
    

    public int getCurrentItemPosition(Fragment fragment)
        return getItemPosition(fragment);
    

    @Override
    public Fragment getItem(int position) 
        return ContentFragment.newInstance(position);
    


public class MyActivity extends FragmentActivity 

static final int NUM_ITEMS = 100000;
public int currentSelectedPage;
private int changeToFragmentIndex;
public DateTime midDate;
MyAdapter mAdapter;
ViewPager mPager;

/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.diary);
    MyApplication application = (MyApplication)getApplication();
    application.dataController.myActivity = this;
    mAdapter = new MyAdapter(getSupportFragmentManager());
    mPager = (ViewPager)findViewById(R.id.pager);
    mPager.setAdapter(mAdapter);
    int newDay = application.daysBetween(DateTime.now(), DateTime.parse(application.day.dateToShortString()));

    this.currentSelectedPage = NUM_ITEMS/2+newDay;
    mPager.setCurrentItem(NUM_ITEMS/2+newDay);
    mPager.setOnPageChangeListener(new SimpleOnPageChangeListener()
        public void onPageSelected(int position)
            currentSelectedPage = position;
            ContentFragment fragment = (ContentFragment) mAdapter.instantiateItem(mPager, currentSelectedPage);
            fragment.loadData();
        
    );




public class ContentFragment extends Fragment 
private View v;
static final int NUM_ITEMS = 100000;

static ContentFragment newInstance(int num) 
    ContentFragment f = new ContentFragment();

    return f;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
    if (container == null)
        return null;
    v = inflater.inflate(R.layout.diarycontent, container, false);
    return v;


@Override
public void onActivityCreated(Bundle savedInstanceState) 
    super.onActivityCreated(savedInstanceState);



@Override
public void onSaveInstanceState(Bundle savedInstanceState)
    super.onSaveInstanceState(savedInstanceState);
    setUserVisibleHint(true);


我收到了这个堆栈跟踪:

Caused by: java.lang.NullPointerException
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:519)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:1 55)
at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:522)

据我了解,这可能是支持包的一个已知问题,一种可能的解决方案是在 onSaveInstanceState 中使用 setUserVisibleHint(true)。但这没有帮助。

有谁知道问题的另一种解决方案或我做错了什么?

【问题讨论】:

嗨@xteci 你解决了这个问题吗?我也遇到这样的错误,还是找不到解决办法 我也是,你们有什么发现吗? @hakim 你可以使用这个答案,它对我有用***.com/questions/18642890/… 【参考方案1】:

一旦我开始在 Tab 中使用 ViewPager 和 FragmentStatePagerAdapter,我就遇到了同样类型的问题。

然后我在所有与此问题相关的论坛上玩了两天,想知道为什么会出现这个问题以及如何解决它,但没有找到任何符合我要求的完美解决方案。

为了避免 NPE 崩溃,我得到了解决方案,使用 FragmentPagerAdapter 而不是 FragmentStatePagerAdapter。当我替换 FragmentPagerAdapter 而不是 FragmentStatePagerAdapter 时,不会遇到 NPE 崩溃问题,但同一页面不会自行刷新以进行进一步导航(这是我的要求)。

最后覆盖 FragmentStatePagerAdapter 上的 saveState 方法,一切正常。

@Override
public Parcelable saveState() 
    // Do Nothing
    return null;

我如何轻松重现此问题: 我正在使用更高版本(4.1)的设备并按照以下步骤操作: 1. 进入设置 -> 开发者选项。 2. 点击“不保留活动”选项。

现在我开始玩我的应用了。

在每次应用程序由于 android.support.v4.app.FragmentManagerImpl.getFragment(Unknown Source) 处的 NPE 而崩溃时覆盖 saveState() 方法之前。但是在覆盖 saveState() 之后没有注册崩溃。

我希望这样做不会有任何问题。

【讨论】:

此解决方案将完全破坏视图状态,并且每个片段都会再次实例化,而不会恢复任何视图状态。仅当您不想恢复视图状态时才有用。并非对所有情况都有用【参考方案2】:

我最初使用@Lalit Kumar Sahoo 建议的解决方案。但是,我注意到一个严重的问题:每次旋转设备时,片段管理器都会添加新片段而不会删除旧片段。所以我进一步搜索,发现了一个带有解决方法建议的错误报告 (post #1)。我使用此修复程序并在我的应用程序中进行了测试,该问题似乎已解决,没有任何副作用:

解决方法:在项目的 src/android/support/v4/app 文件夹中创建自定义 FragmentStatePagerAdapter 并使用它。

package android.support.v4.app;

import android.os.Bundle;
import android.view.ViewGroup;

public abstract class FixedFragmentStatePagerAdapter extends FragmentStatePagerAdapter 

  public FixedFragmentStatePagerAdapter(FragmentManager fm) 
    super(fm);
  

  @Override
  public Object instantiateItem(ViewGroup container, int position) 
    Fragment f = (Fragment)super.instantiateItem(container, position);
    Bundle savedFragmentState = f.mSavedFragmentState;
    if (savedFragmentState != null) 
      savedFragmentState.setClassLoader(f.getClass().getClassLoader());
    
    return f;
  

【讨论】:

【参考方案3】:

你到底为什么这样做:

mPager.setOnPageChangeListener(new SimpleOnPageChangeListener()
    public void onPageSelected(int position)
        currentSelectedPage = position;
        ContentFragment fragment = (ContentFragment) mAdapter.instantiateItem(mPager, currentSelectedPage);
        fragment.loadData();
    
);

这个:

@Override
public Fragment getItem(int position) 
    return ContentFragment.newInstance(position);

实例化片段。

您可以在片段中加载这样的数据:

@Override
public void onActivityCreated(Bundle savedInstanceState) 
super.onActivityCreated(savedInstanceState);
loadData();

【讨论】:

我这样做是因为我在正确更新片段时遇到了一些麻烦。我测试了你的代码,崩溃仍然发生。 这为我解决了,或者真的把它藏起来了***.com/questions/18642890/…

以上是关于使用 Fragments 和 ViewPager 一段时间后,Android 应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

使用 Fragments 和 ViewPager 一段时间后,Android 应用程序崩溃

ViewPager 和 Fragments — 存储 Fragment 状态的正确方法是啥?

将 ViewPager 与 Fragments 一起使用时,在滑动时会破坏 Fragment

如何从 ViewPager 的 onPageSelected AsyncTask 到 Fragments?

响应Activity中的ViewPager2 Fragments事件

使用 Viewpager 从 TabHost 切换到 Fragments:将我的所有代码放在哪里