1

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

我有一个TabSwitcherActivity包含一个ViewPager. 3个片段之间的ViewPager切换,每个片段代表相同信息的不同视图。可能发生某些事件会导致信息过时,因此需要通知片段以刷新视图。为了实现这一点,我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数组中。

4

2 回答 2

5

我正在回答我自己的问题,以防其他人遇到与我类似的问题。我能够根据 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();
    }
}
于 2013-07-18T02:55:26.717 回答
1

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

回复:“我突然想到,如果片段被销毁并重新创建,它们可能没有正确存储在我的 mFragments 数组中。” 不用将片段存储在数组中,而是使用片段管理器按标签或 id 获取片段。

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

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

于 2013-07-17T21:41:03.797 回答