在FragmentPagerAdapter中存储为数组的Android片段在离开并返回应用程序后不会刷新

时间:2013-07-17 21:37:13

标签: android fragment fragmentpageradapter

我遇到一个奇怪的问题,片段视图无法正常刷新,但只有在应用关闭并在一段时间后重新打开后才会发生。

我有TabSwitcherActivity,其中包含ViewPagerViewPager在3个片段之间切换,每个片段代表相同信息的不同视图。某些事件可能会导致信息变得陈旧,因此需要通知片段以刷新视图。为实现此目的,我的TabSwitcherActivity有一个名为notifyDataSetChanged()的方法,它将迭代3个片段并告诉它们刷新。这是(我认为)最相关的代码:

public class TabSwitcherActivity extends FragmentActivity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Used to keep track of the child fragments of this activity so we can update their list adapters.
        mFragments = new ArrayList<Fragment>();

        // Set up the view pager and tab adapter.
        setContentView(R.layout.pager_layout);
        mViewPager = (ViewPager) super.findViewById(R.id.pager);

        mFragments.add(Fragment.instantiate(this, FragmentOne.class.getName()));
        mFragments.add(Fragment.instantiate(this, FragmentTwo.class.getName()));
        mFragments.add(Fragment.instantiate(this, FragmentThree.class.getName()));
        mViewPager.setAdapter(new ListPagerAdapter(super.getSupportFragmentManager(), mFragments));
    }

    public void notifyDataSetChanged() {
        for (Fragment fragment : mFragments) {
        if (fragment instanceof IDataSetChangedListener) {
            ((IDataSetChangedListener) fragment).notifyDataSetChanged();
        }
        }
    }
}

现在,这是第一次启动应用程序时的预期效果。问题是应用程序关闭并在一段时间后重新打开后,在应用程序运行时调用TabSwitcherActivity.notifyDataSetChanged()不会更新片段视图(这在重新启动后第一次启动应用程序时有效)。这让我相信存在一个生命周期情况,我正在处理不正确的碎片。知道这可能是什么吗?我发现如果片段被破坏并重新创建,它们可能没有正确存储在我的mFragments数组中。

2 个答案:

答案 0 :(得分:3)

我正在回答我自己的问题,以防其他人遇到类似的问题。我能够根据invertigo的评论解决问题。我将发布一些代码重要部分的一般化部分。

正如我所怀疑的那样,如果应用程序销毁并重新创建了存储在数组中的片段,则这些片段未正确更新。 (当应用程序关闭并重新打开时,有时会发生这种情况。)因为我在FragmentPagerAdapter实现中使用它来存储我的选项卡的片段,所以删除数组有点棘手。

这是我的旧ListPagerAdapter课程:

public class ListPagerAdapter extends FragmentPagerAdapter {
    private List<Fragment> mFragments;

    public ListPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        mFragments = fragments;
    }

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

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

    @Override
    public String getPageTitle(int position) {
        return ((ITitledFragment) mFragments.get(position)).getTitle();
    }
}

这是我的新实现,它消除了由持有错误片段引用的数组引起的问题:

public class ListPagerAdapter extends FragmentPagerAdapter {    
    private static final int FRAGMENT_ONE_POSITION = 0;
    private static final int FRAGMENT_TWO_POSITION = 1;
    private static final int FRAGMENT_THREE_POSITION = 2;
    private static final int COUNT = 3;

    public ListPagerAdapter(FragmentManager fm) {
        super(fm);  
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
        case FRAGMENT_ONE_POSITION:
            return new FragmentOne();
        case FRAGMENT_TWO_POSITION:
            return new FragmentTwo();
        case FRAGMENT_THREE_POSITION:
            return new FragmentThree();
        }
        return null;
    }

    @Override
    public int getCount() {
        return COUNT;
    }

    @Override
    public String getPageTitle(int position) {
        switch (position) {
        case 0:
            return FragmentOne.getTitle();
        case 1:
            return FragmentTwo.getTitle();
        case 2:
            return FragmentThree.getTitle();
        }
        return null;
    }
}

然后,唯一剩下的问题是如何让我的TabSwitcherActivity类在陈旧时更新所有片段。正如invertigo所指出的,这可以用标签来完成。但是,我决定使用一种方法,其中每个片段在创建时将自身注册到活动,并在销毁之前取消注册。活动可以迭代已注册的片段以更新它们。

来自TabSwitcherActivity的相关代码:

class TabSwitcherActivity extends FragmentActivity {
    private List<Fragment> mFragments;

    private void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Used to keep track of the child fragments of this activity so we can update their list adapters.
        mFragments = new ArrayList<Fragment>();

        // Set up the view pager and tab adapter.
        setContentView(R.layout.pager_layout);
        mViewPager = (ViewPager) super.findViewById(R.id.pager);

        mViewPager.setAdapter(new ListPagerAdapter(super.getSupportFragmentManager()));
    }

    public void startTrackingFragment(Fragment f) {
        mFragments.add(f);
    }

    public void stopTrackingFragment(Fragment f) {
        mFragments.remove(f);
    }

    public void notifyDataSetChanged() {
        for (Fragment fragment : mFragments) {
            if (fragment instanceof IDataSetChangedListener) {
                ((IDataSetChangedListener) fragment).notifyDataSetChanged();
            }
        }
    }
}

有了这个,剩下的就是让片段自己注册更新:

public class FragmentOne extends Fragment implements IDataSetChangedListener {
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        ((TabSwitcherActivity) getActivity()).startTrackingFragment(this);
    }

    public void onDestroy() {
        ((TabSwitcherActivity) getActivity()).stopTrackingFragment(this);
        super.onDestroy();
    }
}

答案 1 :(得分:1)

您可以随时刷新片段的onResume()中的数据,或者在活动的onResume()中调用notifyDataSetChanged()。

re:“我发现如果碎片被破坏并重新创建,它们可能无法正确存储在我的mFragments数组中。” 不是将片段存储在数组中,而是使用片段管理器按标签或id获取片段。

http://developer.android.com/guide/components/fragments.html#Managing

http://developer.android.com/reference/android/app/FragmentManager.html#findFragmentByTag(java.lang.String)