当返回到已停止的活动时,碎片会被旧数据夸大

时间:2014-09-09 15:06:05

标签: android android-activity android-fragments android-viewpager android-pageradapter

活动A有碎片。当它开始对活动B的意图时,那么当B.finish()时,A再次执行onCreate()

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

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

以下是它的实施方式 -

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时没有被实例化?

更新 - 活动碎片生命周期

正如塔尔所说,答案是,活动正在恢复,所以旧的碎片正在被重新连接而不是创建新碎片。

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

新活动

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

无需重新加载。

恢复活动

生命周期:onCreate()==>片段用旧数据膨胀并重新连接==>的onResume()

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

        // 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()

与活动恢复相同,删除旧片段并重新创建。

注意:某些操作系统版本始终会恢复活动,即使打开几秒钟的SettingsActivity,其他(较旧)版本也会一直恢复。

4 个答案:

答案 0 :(得分:2)

如果你发布你在活动A中提交的片段交易,我的答案会更好。

不确定你是否知道 - 如果活动A在从后台堆栈弹出时重新创建 - 这意味着它restored from previous instance state

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

通过检查onCreate()参数是否为空,您可以知道当前是否已通过恢复实例状态调用savedInstanceState

我的假设是您没有检查savedInstanceState,并且无论如何都要执行交易。

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

而不是:

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/fragments.html

答案 1 :(得分:1)

当用户离开活动AB时,FragmentPagerAdapter会将A中的片段与用户界面分离,并且不会销毁实例,以便他们可以当用户返回A后者时重用。

我不确定为什么onCreate A Bprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPacksPagerAdapter = new MyPagerAdapter(fragmentManager); // Set up the ViewPager with the sections adapter. mViewPager = (ViewPager) findViewById(R.id.pager); // Remove the fragments if they already exist. FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction currentTransaction = fragmentManager.beginTransaction(); int count = mPacksPagerAdapter.getCount(); for(int position = 0; position < count; position++) { long itemId = mPacksPagerAdapter.getItemId(position); // fragment name format maintained by adpater: "android:switcher:" + viewId + ":" + id String name = "android:switcher:" + mViewPager.getId() + ":" + itemId; Fragment fragment = fragmentManager.findFragmentByTag(name); if(fragment != null) { // if fragment instance exists, destroy it. currentTransaction.remove(fragment); } } // commit all the operations with state loss. currentTransaction.commitAllowingStateLoss(); // immediately execute the operations fragmentManager.executePendingTransactions(); // Rest of your code follows here. .... } 完成后被调用。如果您不希望将旧片段附加到用户界面,而是希望重新创建它们,则需要明确销毁它们。

{{1}}

答案 2 :(得分:0)

我认为你应该将你的片段添加到你的视图并提交。

在你的&#34; onCreate&#34;。

中写下这样的东西
fragmentTransaction.add(R.id.container, YOUR_FRAGMENT);
fragmentTransaction.commit();

或替换旧的。

答案 3 :(得分:0)

这是广告宣传的行为:您的片段正在恢复

实际上,还应该注意到,仅仅是重新创建活动A的机会。 B完成后,活动A可能仍然存在,这不会再次导致执行onCreate。


为什么没有调用newInstance

  

这是因为片段实际上位于被杀死活动的FragmentManager中。因此,在重新创建活动时会恢复它们。片段的标签通常是:   的 "android:switcher:" + your_pager_id + ":" + your_fragment_position