Activity的启动模式简介
在android应用开发中,打造良好的用户体验是非常重要的。而在用户体验中,界面的引导和跳转是值得深入研究的重要内容。在开发中,与界面跳转联系比较紧密的概念是Task(任务)和Back Stack(回退栈)。activity的启动模式会影响Task和Back Stack的状态,进而影响用户体验。除了启动模式之外,Intent类中定义的一些标志(以FLAG_ACTIVITY开头)也会影响Task和Back Stack的状态。
Task是一个存在于Framework层的概念,容易与它混淆的有Application(应用)和Process(进程)。在开始介绍Activity的启动模式的使用之前,首先对这些概念做一个简单的说明和区分。
一 Application,Task和Process的区别与联系
1 <?xml version="1.0" encoding="utf-8"?>
2 <manifest android:versionCode="1"
3 android:versionName="1"
4 xmlns:android="http://schemas.android.com/apk/res/android"
5 package="com.example.android.myapp">
6
7 <application android:label="@string/app_name">
8 <activity android:name=".MyActivity" android:label="@string/app_nam">
9 <intent-filter>
10 <action android:name="android.intent.action.MAIN" />
11 <category android:name="android.intent.category.LAUNCHER" />
12 </intent-filter>
13 </activity>
14 <receiver android:name=".MyReceiver"/>
15 <provider android:name=".MyProvider"/>
16 <service android:name=".MyService"/>
17 </application>
18 </manifest>
application是由四大组件组成的,之前我们讲过,在app安装时主要就是读取manifest的信息,将所有的组件解析出来,以便在运行时对组件进行实例化和调度。
task是一组相互关联的activity的集合,它是存在于framework层的一个概念,控制界面的跳转和返回。这个task存在于一个称为back stack的数据结构中,也就是说,framework是以栈的形式管理用户开启的activity。这个栈的基本行为是,当用户在多个activity之间跳转时,执行压栈操作,当用户按返回键时,执行出栈操作。任务栈的操作可以如下图所示:
process一般翻译成进程,进程是操作系统内核中的一个概念,表示直接受内核调度的执行单位。在应用程序的角度看,我们用java编写的应用程序,运行在dalvik虚拟机中,可以认为一个运行中的dalvik虚拟机实例占有一个进程,所以,在默认情况下,一个应用程序的所有组件运行在同一个进程中。但是这种情况也有例外,即,应用程序中的不同组件可以运行在不同的进程中。只需要在manifest中用process属性指定组件所运行的进程的名字。如下所示,这样的话这个MyActivity会运行在一个独立的进程remote中:
1 <activity android:name=".MyActivity" android:label="@string/app_nam"
2 android:process=":remote">
3 </activity>
二 Activity四种启动模式详解
activity有四种启动模式,分别为standard(标准),singleTop(栈顶),singleTask(单任务),singleInstance(单例)。如果要使用这四种启动模式,必须在manifest文件中<activity>标签中的launchMode属性中配置,如下:
1 <activity android:name=".app.InterstitialMessageActivity"
2 android:label="@string/interstitial_label"
3 android:theme="@style/Theme.Dialog"
4 android:launchMode="singleTask"
5 </activity>
Activity的启动模式也可以在intent的标志位中设置,标志位所代表的启动方式我们能从字面意思上清晰的了解到:
1 Intent.FLAG_ACTIVITY_NEW_TASK
2 Intent.FLAG_ACTIVITY_SINGLE_TOP
3 Intent.FLAG_ACTIVITY_CLEAR_TOP
4 Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
下面就简单介绍一下这四种启动方式,当然要更好地理解还是推荐看官方文档和源码。
standard(FLAG_ACTIVITY_NEW_TASK)
标准启动模式,也是activity的默认启动模式。在这种模式下启动的activity可以被多次实例化,即在同一个任务中可以存在多个activity的实例,每个实例都会处理一个Intent对象。如果Activity A的启动模式为standard,并且A已经启动,在A中再次启动Activity A,即调用startActivity(new Intent(this,A.class)),会在A的上面再次启动一个A的实例,即当前的桟中的状态为A-->A。
singleTop(FLAG_ACTIVITY_SINGLE_TOP)
如果一个以singleTop模式启动的activity的实例已经存在于任务桟的桟顶,那么再启动这个Activity时,不会创建新的实例,而是重用位于栈顶的那个实例,并且会调用该实例的onNewIntent()方法将Intent对象传递到这个实例中。举例来说,如果A的启动模式为singleTop,并且A的一个实例已经存在于栈顶中,那么再调用startActivity(new Intent(this,A.class))启动A时,不会再次创建A的实例,而是重用原来的实例,并且调用原来实例的onNewIntent()方法。这是任务桟中还是这有一个A的实例。
如果以singleTop模式启动的activity的一个实例已经存在与任务桟中,但是不在桟顶,那么它的行为和standard模式相同,也会创建多个实例。
singleTask(FLAG_ACTIVITY_CLEAR_TOP)
谷歌的官方文档上称,如果一个activity的启动模式为singleTask,那么系统总会在一个新任务的最底部(root)启动这个activity,并且被这个activity启动的其他activity会和该activity同时存在于这个新任务中。如果系统中已经存在这样的一个activity则会重用这个实例,并且调用他的onNewIntent()方法。即,这样的一个activity在系统中只会存在一个实例。
singleInstance(FLAG_ACTIVITY_BROUGHT_TO_FRONT)
总是在新的任务中开启,并且这个新的任务中有且只有这一个实例,也就是说被该实例启动的其他activity会自动运行于另一个任务中。当再次启动该activity的实例时,会重用已存在的任务和实例。并且会调用这个实例的onNewIntent()方法,将Intent实例传递到该实例中。和singleTask相同,同一时刻在系统中只会存在一个这样的Activity实例。