activity被回收,fragment恢复处理

来源:互联网 发布:淘宝男裤子店铺排名 编辑:程序博客网 时间:2024/04/30 07:31


例如activity放在后台一段时间,当activity被回收之后,再重新进入activity的时候,会重新调用onCreate(),并且savedInstanceState不再是null,因此可以判断出是否被回收。

onCreate中不要重复创建fragment,通过tag去获得figment即可。

从谷歌开源项目中得到的的启示,源码:

   @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(getContentViewResId());        if (getIntent().hasExtra(Intent.EXTRA_TITLE)) {            setTitle(getIntent().getStringExtra(Intent.EXTRA_TITLE));        }        final String customTitle = getIntent().getStringExtra(Intent.EXTRA_TITLE);        setTitle(customTitle != null ? customTitle : getTitle());        if (savedInstanceState == null) {            mFragment = onCreatePane();            mFragment.setArguments(intentToFragmentArguments(getIntent()));            getFragmentManager().beginTransaction()                    .add(R.id.root_container, mFragment, "single_pane")                    .commit();        } else {            mFragment = getFragmentManager().findFragmentByTag("single_pane");        }    }
源码摘自:

com.google.samples.apps.iosched.ui.SimpleSinglePaneActivity



自己精简一下就是:

public class MainActivity extends AppCompatActivity {    private BlankFragment mFragment;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        if (savedInstanceState == null) {            mFragment = new BlankFragment();            getSupportFragmentManager().beginTransaction()                    .add(R.id.root_container, mFragment, "single_pane")                    .commit();        } else {            mFragment = (BlankFragment) getSupportFragmentManager().findFragmentByTag("single_pane");        }        Log.e("MainActivity", "savedInstanceState=" + savedInstanceState + " mFragment=" + mFragment);    }}

打印了两个Log,一个是首次创建,另一个是回收了之后创建。

11-22 12:55:43.940 24433-24433/com.example.baidu.test E/MainActivity: savedInstanceState=null mFragment=BlankFragment{585c98a id=0x7f0b0055 single_pane}


11-22 12:57:36.576 24433-24433/com.example.baidu.test E/MainActivity: savedInstanceState=Bundle[{android:viewHierarchyState=Bundle[mParcelledData.dataSize=680], android:support:fragments=android.support.v4.app.FragmentManagerState@ea89abf}] mFragment=BlankFragment{baa458c #0 id=0x7f0b0055 single_pane}


测试的时候可以设置手机【不保留活动】,这样可以快速的模拟回收的情况,小米手机有这个功能。





Activity被回收,系统为什么会保存Fragment呢?来分析一下FragmentActivity源码:

/**
     * Save all appropriate fragment state.     */    @Override    protected void onSaveInstanceState(Bundle outState) {        super.onSaveInstanceState(outState);        Parcelable p = mFragments.saveAllState();        if (p != null) {            outState.putParcelable(FRAGMENTS_TAG, p);//这里保存了Fragment数据        }        if (mPendingFragmentActivityResults.size() > 0) {            outState.putInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG, mNextCandidateRequestIndex);            int[] requestCodes = new int[mPendingFragmentActivityResults.size()];            String[] fragmentWhos = new String[mPendingFragmentActivityResults.size()];            for (int i = 0; i < mPendingFragmentActivityResults.size(); i++) {                requestCodes[i] = mPendingFragmentActivityResults.keyAt(i);                fragmentWhos[i] = mPendingFragmentActivityResults.valueAt(i);            }            outState.putIntArray(ALLOCATED_REQUEST_INDICIES_TAG, requestCodes);            outState.putStringArray(REQUEST_FRAGMENT_WHO_TAG, fragmentWhos);        }    }
从源码中得知,当Activity调用onSaveInstanceState方法的时候,会保存当前Activity里面的所有Fragment,保存在了一个Bundle里,key就是FRAGMENTS_TAG。

其实这个Bundle会在Activity恢复的时候传给onCreate,这就是为什么onSaveInstanceState不是null了。

有人会问什么时候会调用onSaveInstanceState方法?用最简洁的一句话:当Activity不可见的时候就会执行nSaveInstanceState。例如被另一个Activity覆盖,按Home键回到桌面等等。当然你主动结束Activity不会执行。调用onSaveInstanceState保存的不只是fragment,还保存了View的状态,只保存了带id的View的状态,不带id不会保存的。


其实回收之后恢复是很麻烦的,得到了Fragment后,你会发现成员变量并没有恢复,只有View某些状态被恢复了,如果完全重现被回收那一刻的所有状态,还需要考虑在Fragment里面重写onSaveInstanceState方法,来保存一些数据,呵呵,工作量不小啊,非特殊情况下,我不建议这么做。

我一般的做法都是重新创建Activity和Fragment:

public class MainActivity extends AppCompatActivity {    static final String FRAGMENTS_TAG = "android:support:fragments";    private BlankFragment mFragment;    @Override    protected void onCreate(Bundle savedInstanceState) {        //删除保存的Fragment,也可以重写onSaveInstanceState方法不让其保存        if (savedInstanceState != null) {            savedInstanceState.putParcelable(FRAGMENTS_TAG, null);        }        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mFragment = new BlankFragment();        getSupportFragmentManager().beginTransaction()                .add(R.id.root_container, mFragment, "single_pane")                .commit();    }}

你可以记住重要的关键信息,来恢复这个Activiy。例如当前Activity是一篇文章,你只需要在onSaveInstanceState保存文章id,等恢复的时候直接根据id从服务器拉取就好了。

如果你的Activity在启动时的Intent里面有文章id,那就简单了,在回收恢复的时候,直接这样仍然得到文章id:String id = getIntent().getStringExtra("article_id");,这样根本不用你主动保存。使用Intent的时候必须序列化的原因:只有被序列化的对象和基本数据类型才可以保存在磁盘上,这样内存被干掉,仍然可以将他们从磁盘上恢复到内存中。


0 0
原创粉丝点击