通过前面的学习,Activity的基本使用都已掌握,接下来一起来学习更高级的一些内容。
Android采用任务栈(Task)的方式来管理Activity的实例。当启动一个应用时,Android就会为之创建一个任务桟。先启动的Activity压在栈底,后启动的Activity放在找顶,通过启动模式可以控制Activity在任务栈中的加载情况。本节将针对Activity的任务栈和启动模式进行详细的讲解。
一、Activity任务栈
在开发Android应用时,经常会涉及一些消耗大量系统内存的情况,例如视频播放、大量图片或者程序中开启多个Activity没有及时关闭等,会导致程序出现错误。为了避免这种问题,Google提供了一套完整的机制让开发人员控制 Android中的任务栈。
Android系统中的任务栈,类似于一个容器,用于管理所有的Activity实例。在存放Activity时,满足“先进后出 (First-In/Last-Out )"的原则。接下来通过一个图例来说明任务找中如何存放Activity,如下图所示。
从上图可以看出,先加入任务栈中的Activity会处于容器下面,后加入的处于容器上面,而从任务栈中取出Activity 出的是最底端的Activity。
但是使用任务栈有以下缺点:
每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出。这样就造成了用户体验差, 需要点击多次返回才可以把程序退出。
每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余, 重复数据太多, 会导致内存溢出的问题(OOM)。
为了解决任务栈产生的问题,Android为Activity设计了启动模式,那么下面的内容将介绍Android中Activity的启动模式。
二、Activity启动模式
在实际开发中,应根据特定的需求为每个Activity指定恰当的启动模式。Activity的启动模式有4种,分别是standard、singleTop、singleTask和singlelnstance。在AndroidManifest.xml中,通过<activity>标签的android:launchMode属性可以设置启动模式。下面针对这4种启动模式分别进行详细的讲解。
1、standard模式
standard是Activity默认的启动模式,在不指定Activity启动模式的情况下,所有Activity 使用的都是standard模式。因此,前面使用的Activity都是standard启动模式。
在standard模式下,每当启动一个新的Activity,它就会进入任务栈,并处于栈顶的位置,对于使用standard模式的Activity,系统不会判断该Activity在栈中是否存在,每次启动都会创建一个新的实例。
接下来通过一个图例展示standard模式下Activity在栈中的存放情况,如下图 所示。
从上图中可以看出,在standard 启动模式下Activity01最先进栈,其次是Activity02,最后是 Activity03;出栈时,Activity03最先出栈,其次是Activity02,最后是Activity01,满足“先进后出”的原则。
2、singleTop模式
singleTop模式与standard类似,不同的是,当启动的Activity已经位于栈顶时,则直接使用它不创建新的实例。如果启动的Activity没有位于栈顶时,则创建一个新的实例位于栈顶。
接下来通过一个图例展示singleTop模式下Activity在栈中的存放情况,如下图所示。
从上图中可以看出,当前栈顶中的元素是 Activity03,如果再次启动的界面还是Activity03,则复用当前找顶的Activity实例,如果再次启动的界面没有位于栈顶,则会重新创建一个实例。
3、singleTask模式
如果希望Activity在整个应用程序中只存在 一个实例,可以使用singleTask模式,当Activity 的启动模式指定为singleTask,每次启动该Activity时,系统首先会检查栈中是否存在该活动的实例,如果发现已经存在则直接使用该实例, 并将当前Activity之上的所有Activity出栈,如果没有发现则创建一个新的实例。
接下来通过一个图例展示singleTask模式Activity在找中的存放情况,如下图所示 。
从上图可以看出,当再次启动Activity02时,并没有新创建实例,而是将Activity03实例移除,复用Activity02实例,这就是singleTask模式,让某个Activity在当前栈中只存在一个实例。
4、singleInstance模式
在程序开发中,如果需要Activity在整个系统中都只有一个实例,这时就需要用到singlelnstance模式。不同于上述三种模式,指定为singlelnstance模式的Activity会启动新的任务栈来管理这个Activity。
singlelnstance模式加载Activity时,无论从哪个任务栈中启动该Activity,只会创建一个Activity实例,并且会使用一个全新的任务栈来装载该Activity实例。采用这种模式启动Activity 会分为以下两种情况:
第一种:如果要启动的Activity不存在,系统会先创建一个新的任务栈,再创建该 Activity的实例,并把该Activity加入栈顶,如下图所示。
第二种:如果要启动的Activity已经存在,无论位于哪个应用程序或者哪个任务钱中,系统都会把该Activity所在的任务栈转到前台,从而使该Activity显示出来。
至此,Activity的4种启动模式已经讲解完成,在实际开发中需要根据实际情况来选择合适的启动模式。
三、Activity栈其他配置
在实际开发中除了配置上述的android:launchMode属性来设置启动模式,还常会配置以下属性来辅助管理Activity任务栈:
android:taskAffinity
android:allowTaskReparenting
android:clearTaskOnLaunch
android:alwaysRetainTaskState
android:finishOnTaskLaunch
接下来通过两方面来学习这5个属性。
1、Affinity
默认情况下,一个应用程序中的所有Activity都有一个Affinity,这让它们属于同一个Task。当然,每个Activity也可以通过 <activity>中的android:taskAffinity属性设置单独的Affinity。 不同应用程序中的Activity可以共享同一个Affinity,同一个应用程序中的不同Activity 也可以设置成不同的Affinity。 Affinity属性在以下2种情况下起作用:
当启动 Activity的Intent对象包含FLAG_ACTIVITY_NEW_TASK标记时,系统会为需要启动的Activity寻找与当前Activity不同Task。如果要启动的 Activity的Affinity属性与当前所有的Task的Affinity属性都不相同,系统会新建一个带那个Affinity属性的Task,并将要启动的Activity压到新建的Task栈中;否则将Activity压入那个Affinity属性相同的栈中。
如果一个Activity的android:allowTaskReparenting属性为true, 那么它可以从一个Task(Task1)移到另外一个有相同Affinity的Task(Task2)中(Task2带到前台时)。 如果一个.apk文件从用户角度来看包含了多个"应用程序",你可能需要对那些 Activity赋不同的Affinity值。
2、清空栈
当用户长时间离开Task(当前Task被转移到后台)时,系统会清除Task中栈底Activity外的所有Activity 。这样,当用户返回到Task时,只留下那个Task最初始的Activity了。我们可以通过修改下面这些属性来改变这种行为:
android:alwaysRetainTaskState: 如果栈底Activity的这个属性被设置为true,上述的情况就不会发生。 Task中的所有Activity将被长时间保存。
android:clearTaskOnLaunch:如果栈底Activity的这个属性被设置为true,一旦用户离开Task, 则 Task栈中的Activity将被清空到只剩下栈底Activity。这种情况刚好与 android:alwaysRetainTaskState相反。即使用户只是短暂地离开,Task也会返回到初始状态 (只剩下栈底Acitivty)。
android:finishOnTaskLaunch 与android:clearTaskOnLaunch相似,但它只对单独的Activity操 作,而不是整个Task。它可以结束任何Activity,包括栈底的Activity。 当它设置为true时,当前的Activity只在当前会话期间作为Task的一部分存在, 当用户退出Activity再返回时,它将不存在。
本期的内容较深,不是很好懂,如果不能完全理解先知道就行,等后期有一定经验后再来研究。
今天就先到这里,如果有问题欢迎留言一起探讨,也欢迎加入Android零基础入门技术讨论微信群,共同成长!