# Android APP回收
1. Application回收
测试环境:
a). 新建一个Android工程,自定义一个Application和Activity A、B,启动入口为A,A启动后,立即启动B;
b). B启动后,按home键放入后台,在开发环境DDMS中点击关闭进程,然后回到手机桌面,点击APP图标进入应用;
测试现象:
a)、执行了Application的onCreate方法,执行了Activity B的onCreate方法,**并没有执行Activity A的onCreate方法**
#### 结论:
a)、Application被系统回收后,再次进入APP,APP会启动Application和被回收前(Task顶)的Activity
b)、在Application建议不要存成员变量、静态变量、数组、数据结构等与Activity、Service、fragment等常用组件生命周期相关的数据。
c)、Application中能够维护的是,和ApplicationContext生命周期一致的组件和数据,如lib库的初始化,Toast显示、关闭等。
d)、两个组件之前的数据传递,应该使用intent传值,setResult、eventbus、广播等其他方式进行传递,不要讲要传递的数据保存在Appcation里面去做读取操作。
e)、不建议在Application中保存对有Activity、Service、fragment等有生命周期的系统组件或其它被管理的组件持有引用,因为这样做有可能会带来一定的内存泄漏,需要妥善引用和释放。
2. Activity回收机制
Activity的回收处理在日常项目中相对比较容易处理,重写onSaveInstanceState方法,存入需要保存的数据,在onCreate中取出保存数据即可。
a).切换到后台时,依次执行onPause 、onSaveInstanceState 、onStop方法;
b).进入系统设置,切换系统语言,在回到桌面,启动应用,当前activity开始重启
c).activity在重启时,依次执行onDestroy、onCreate、onStart、onRestoreInstanceState、onResume方法。
#### 结论
可以将每一个Activity作为单独的模块来处理,这个模块的输入,输出。并且在他的生命周期中,能接受人机交互的数据输入和其它组件(如广播,Service、接口回调)的传值,这部分数据暂称为过程中输入。当然它也可以发送事件到其它组件去,这里暂不讨论。
a).输入:建议使用Intent传值,在activity被回收后重启时,仍然能从getIntent中获取到输入
b).输出:建议使用setResult方式输出,startActivityFroResult启动的Activity B, 系统被重启后,仍然能通过setResult将Activity B中的数据返回到A的onActivityResult中(如果用广播需要使用粘性广播)
c).过程中输入,这部分的数据需要开发者根据Activity的业务流程选择性或是全部存储到onSaveInstanceState中,在onCreate方法里面,如果savedInstanceState参数不为空,则表示该activity是被系统重启过了的activity,需要从savedInstanceState取出数据,恢复activity状态。
3. Fragment回收机制
Fragment一般会被Activity加载,所以当Activity被重启时,所以Fragment的回收机制需要首先在Activity里面处理
Activity中处理如下代码:
'' if (savedInstanceState == null) {
'' BackUpFragment f = BackUpFragment.newInstance("testbackUp");
'' FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
'' fragmentTransaction.replace(R.id.fg_backup, f, "tag");
'' fragmentTransaction.commit();
'' } else {
'' BackUpFragment f = (BackUpFragment) getSupportFragmentManager().findFragmentByTag("tag");
'' if (f == null) {
'' // 创建fragment
'' f = BackUpFragment.newInstance("testbackUp");
'' FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
'' fragmentTransaction.replace(R.id.fg_backup, f, "tag");
'' fragmentTransaction.commit();
'' }
'' }
需要注意的时候,将Fragment放入容器时,记得设置Tag,重启时可以根据Tag找到Fragment
Fragment中的处理代码为:
'' @Override
'' public View onCreateView(LayoutInflater inflater, ViewGroup container,
'' Bundle state) {
'' if (state != null) {
'' LogUtils.v("true");
'' mData = state.getString("key");
'' } else {
'' LogUtils.v("false");
'' }
'' View rootView = inflater.inflate(R.layout.fg_backup, container, false);
''
'' TextView tv = (TextView) rootView.findViewById(R.id.tv_fg_show);
'' tv.setText(mData);
'' return rootView;
''
'' }
''
'' @Override
'' public void onSaveInstanceState(Bundle outState) {
'' super.onSaveInstanceState(outState);
'' outState.putString("key", mData);
'' }
另外在Fragment嵌套在ViewPager的时候,并非自己添加fragment到FragmentManager中的情况,
需要查看下层代码在添加时是否有给Fragment设置tag,如果设置,则可以在重启后通过代码找到Fragment:
'' if (savedInstanceState != null) {
'' for (int i=0; i<4; i++) {
'' BackUpFragment fragment = (BackUpFragment)
'' getSupportFragmentManager().findFragmentByTag("android:switcher:" + pager.getId() + ":" + i);
'' if (fragment == null) {
'' fragment = BackUpFragment.newInstance("fragment" + i);
'' } else {
'' LogUtils.v("TableLayoutFragmentActivity getBackUp fragment "+i);
'' }
'' mFragmentList.add(fragment);
'' }
'' } else {
'' for (int i=0; i<4; i++) {
'' BackUpFragment fragment = BackUpFragment.newInstance("fragment"+i);
'' mFragmentList.add(fragment);
'' }
'' }
####结论
Fragment回收策略的考虑比Activity麻烦,总结而言有两点:
a).添加Fragment的时候记得给Tag,在Activity中通过fragment通过Tag找到可以使用的Fragment
b).在Fragment中通过onSaveInstanceState方法保存过程输入数据,重启后在onCreateView中获取过程输入数据