初看这个博文名,我都蒙蔽了,Activity的启动模式居然能扯到内存问题,还有内存泄漏问题,
WTF!!!不要方,小司机我带你理解和稍微深入的探讨一下Activity的四种启动模式对内存的影响和在何种情况下应该使用这四大法王之一呢?
不写Demo,你就听我说就行了。
Activity的启动方式有四种:
standard
singleTop
singleTask
singleInstance
讲解启动模式之前有必要先讲解一下“任务栈”的概念;
任务栈
每个应用都有一个任务栈,是用来存放Activity的,功能类似于函数调用的栈,先后顺序代表了Activity的出现顺序;比如打开ActivityYa–>ActivityMai–>ActivityDai,则任务栈相应的顺序图为:
接着我们来设置Activity的启动模式只需要在AndroidManifest.xml里对应的标签设置Android:launchMode属性,例如:
启动模式解析:
每次激活Activity时(startActivity),都创建Activity实例,并放入任务栈;
默认模式,可以不用写配置。在这个模式下,都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加(记住,可以允许叠加,就代表可以重复创建此Activity)。
示例如下图:
假如我点击了Activity1中的按钮1和按钮2(牛逼的人在瞬间同时点击,暂不考虑后退的问题了):
如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。
示例如下图:
假如我点击了Activity1中的按钮1和按钮2(牛逼的人在瞬间同时点击,暂不考虑后退的问题了):这次点击按钮1,因为栈顶存在Activity1,所以不会重复创建,如果不是栈顶,则会创建。
如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈(销毁)。如果栈中不存在该实例,将会创建新的实例放入栈中。
示例如下图:
假如我点击了Activity1中的按钮1和按钮2,又点了按钮1(牛逼的人在瞬间顺序点击而不发生跳转,暂不考虑后退的问题了):
在一个新栈中创建该Activity实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity的实例存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。
假如我点击了Activity1中的按钮1(只点击了按钮1):
这四种模式中的Standard模式是最普通的一种,没有什么特别注意,而SingleInstance模式是整个系统的单例模式,在我们的应用中一般不会应用到,所以,这里就具体讲解 SingleTop 和 SingleTask模式的运用场景:
最常见的应用场景就是保持我们应用开启后只有一个Activity的实例,最典型的例子就是应用中展示的主页(Home页)。假设用户在主页跳转到其它页面,执行多次操作后想返回到主页,如果不使用SingleTask模式,在点击返回的过程中会多次看到主页,这明显就是设计不合理了。
如果你在当前的Activity中又要启动同类型的Activity,此时建议将此类型Activity的启动模式指定为SingleTop,可以减少Activity的创建,节省内存!
这里还需要考虑一个Activity跳转时携带页面参数的问题。
因为当一个Activity设置了SingleTop或者SingleTask模式后,跳转此Activity出现复用原有Activity的情况时,此Activity的onCreate方法将不会再次执行!onCreate方法只会在第一次创建Activity时被执行。
而一般onCreate方法中会进行该页面的数据初始化、UI初始化,如果页面的展示数据无关页面跳转传递的参数,则不必担心此问题,若页面展示的数据就是通过getInten() 方法来获取,那么问题就会出现:getInten()获取的一直都是老数据,根本无法接收跳转时传送的新数据!
根据上面启动模式的介绍可得知,当CourseDetailActivity处于栈顶时,再次跳转页面到CourseDetailActivity时会直接复用原有的Activity,而且此页面需要展示的数据是从getIntent()方法得来,可是initData()方法不会再次被调用,此时页面就无法显示新的数据。
当然这种情况系统早就为我们想过了,这时我们需要另外一个回调 onNewIntent(Intent intent)方法,此方法会传入最新的intent,这样我们就可以解决上述问题。这里建议的方法是重新去setIntent,然后重新去初始化数据和UI,代码如下所示:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
initData();
initView();
}
文章部分内容参考了《Android开发艺术探索》,后续传上来。