返回到已停止的活动时,碎片会被旧数据夸大 [英] Fragments being inflated with old data, when going back to an activity that was stopped

查看:71
本文介绍了返回到已停止的活动时,碎片会被旧数据夸大的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

活动A有片段.当它开始活动B的意图时,然后当B.finish()时,A再次执行onCreate().

Activity A has fragments. When it starts an intent to activity B, then when B.finish(), A executes onCreate() again.

但是这次,即使A.onCreate()具有新的PacksPagerAdapter和新的ViewPager,这些片段也会显示旧数据.

But this time, even though A.onCreate() has a new PacksPagerAdapter and a new ViewPager, the fragments are shown with old data.

我可以看到每个片段都执行了onCreateView(),但是由于没有调用static newInstance(),它仍然具有旧的参数.调用FragmentPagerAdapter的getItem(position)时会创建参数.

I can see that that onCreateView() is executed for each fragment, but it still has the old arguments since the static newInstance() wasn't called. Arguments are created when FragmentPagerAdapter's getItem(position) is called.

这是它的实现方式-

public class PackActivity extends Activity {
    ...
    PacksPagerAdapter mPacksPagerAdapter;
    ViewPager mViewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mPacksPagerAdapter = new MyPagerAdapter(getFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mPacksPagerAdapter);
        mViewPager.setOffscreenPageLimit(PACK_PAGES - 1);

        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                    @Override
                    public void onPageSelected(int position) {
                        actionBar.setTitle(...);
                    }
                });

    }
    ...
}

public class MyPagerAdapter extends FragmentPagerAdapter {
...
    @Override
    public Fragment getItem(int position) {
        // getItem is called to instantiate the fragment for the given page.
        // Return a PlaceholderFragment (defined as a static inner class
        // below).
        return PackFragment.newInstance(myData);
    }
...
}

public class PackFragment extends Fragment {
...
    public static PackFragment newInstance(PackInfo pack) {
        PackFragment fragment = new PackFragment();

        Bundle bdl = new Bundle(2);
        bdl.putSerializable(EXTRA_PACK, pack);
        bdl.putInt(EXTRA_PACK_POSITION, pack.packNumber);
        fragment.setArguments(bdl);

        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View packView = inflater.inflate(R.layout.pack_fragment, container, false);

        // this has the old argument, since newInstance(...) wasn't called      
        PackInfo pack = (PackInfo) getArguments().getSerializable(EXTRA_PACK);
        ...

        return packView;
    }

...
}

有人知道为什么在活动A的第二次创建时未实例化新片段吗?

Any idea why new fragments aren't being instantiated on the 2nd creation of activity A?

正如塔尔(Tal)所说,答案是活动正在恢复,所以旧的片段被重新附加,而不是创建新的片段.

The answer is, as Tal said, is that activity is being restored, so old fragments are being reattached instead of creating new ones.

花了很多时间研究这个问题之后,我发现活动片段生命周期通常有3个场景.以下是方案,生命周期以及如何重新加载片段的旧数据:

After spending a lot of time studying this, I've found that there are typically 3 scenarios for activity-fragments lifecycle. Here are the scenarios, the lifecycle and how to reload fragment's old data:

新活动

生命周期:onCreate()==> onResume()==>片段已创建并附加

Lifecycle: onCreate() ==> onResume() ==> Fragments are created and attached

无需重新加载.

恢复的活动

生命周期:onCreate()==>随旧数据膨胀并重新附加的片段==> onResume()

Lifecycle: onCreate() ==> Fragments inflated with old data and reattached ==> onResume()

在onResume()中,手动或使用适配器自动删除所有片段并创建新片段-

In onResume(), remove all fragments and create new ones, either manually or automatically using an adapter -

        // Remove all fragments
        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        for (int i = BuildConfig.PACK_PAGES - 1; i >= 0; i--) {
            Fragment f = findFragmentByPosition(i);
            if (f != null)
                fragmentTransaction.remove(f);
        }
        fragmentTransaction.commit();

        // This will force recreation of all fragments
        viewPager.setAdapter(packsPagerAdapter);

恢复的活动

生命周期:onResume()

Lifecycle: onResume()

与活动还原相同,删除旧片段并重新创建.

Same as activity restore, remove old fragments and recreate.

注意:某些操作系统版本始终会恢复活动,即使打开SettingsActivity几秒钟也是如此,而其他(旧)版本将始终恢复.

Note: Some OS versions always restores activity, even when opening a SettingsActivity for a few seconds, and other (older) versions will always resume.

推荐答案

如果您将在活动A中提交的分段事务发布,我的答案会更好.

my answer will be better if you'll post the fragment transaction you commit in activity A.

不确定您是否知道-如果活动A从后堆栈弹出时重新创建,则表示它

not sure that you know it or not - if Activity A is re-created when it pop back from back stack - it means that it restored from previous instance state.

不应再次执行事务,因为-它已经通过super.onCreate()Activity方法自动发生.实际上,如果您要在这种情况下执行片段事务-您会导致同一片段被添加两次(2个实例)

in that case, you should not perform the transaction again, because - it already happens automatically via the super.onCreate() Activity method. in fact, if you'll perform the fragment trasaction in that case - you'll cause the same fragment to be added twice (2 instances)

通过检查savedInstanceState参数是否为空,可以从恢复实例状态中了解当前是否调用了onCreate().

you can know if currently onCreate() been called from restoring instance state by checking if savedInstanceState parameter is null or not.

我的假设是您没有检查savedInstanceState以及仍在执行交易.

my assumption is that you are not checking savedInstanceState, and performing the transaction anyway.

如果我是对的,那么以下更改应该可以解决片段重复的问题:

if I'm right, then the following change should fix the fragment duplication problem:

代替:

public static class ActivityA extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        performFragmentTransaction();

}

写:

public static class ActivityA extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null) {
           performFragmentTransaction();
        }
}

更多信息-- http://developer.android.com/guide/components/fragment.html

这篇关于返回到已停止的活动时,碎片会被旧数据夸大的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆