这几天时间比较充裕,多写几篇。今天来写一下activity启动模式。在昨天已经说过了四种luncher的内容,下面来用代码熟悉它们具体是怎么实现的。
standard
standard 是活动默认的启动模式,在不进行显式指定的情况下,所有活动都会自动使用这种启动模式。因此,到目前为止我们写过的所有活动都是使用的 standard 模式。经过上一节的学习,你已经知道了 Android 是使用返回栈来管理活动的,在 standard 模式(即默认情况)下,每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用 standard 模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
Log.v("lixinlalal","FirstActivity");
Button button=(Button)findViewById(R.id.button);
button.setOnClickListener(newView.OnClickListener() {
@Override
public voidonClick(View v) {
Intent intent =newIntent(FirstActivity.this,FirstActivity.class);
startActivity(intent);
写的demo中我们设置了一个按键,用于启动一个活动,点击button以后让它启动自己这个页面,会发现你每点击一次button,页面会刷新一下,生成一个新的FirstActivity,从log中也可以看到

我们点击了3次,系统生成了3个返回栈的实例存放在返回栈当中,点击返回,会回退到前一个返回栈实例对应的activity,需要返回4次才能退出这个程序。用图形表现如下

singleTop
singleTop在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。

在AndroidManifest的活动属性设置那里添加红线部分的代码,表示activity的启动模式设定为singletop,运行代码。

不管点击多少次都不会再次调用FirstActivity的onCreate方法,也就是说singleTop模式启动活动时如果发现返回栈的栈顶已经是该活动,则直接使用它,不会重建一个返回栈的实例,从手机端的反应的就是点击button以后不会又刷新页面的动画,且点击退出只需要点击一次。
下面再添加一个activity试一下


代码在上面,FirstActivity的button点击后后启动SecondActivity,SecondActivity页面的button2会启动FirstActivity。

进入app以后多次点击button打印的log如上图。第一次点击FirstActivity的button会先检查栈顶是不是SecondActivity,此时栈顶是FirstActivity,会生成一个新的返回栈实例,存放SecondActivity;在SecondActivity点击button,会检查栈顶是不是FirstActivity,此时栈顶是SecondActivity,也会重新生成一个栈顶实例,后面的点击事件同理。点击返回需要返回6次才能退出程序。

singleTask
singleTop 模式可以很好地解决重复创建栈顶活动的问题,但如果该活动并没有处于栈顶的位置,还是可能会创建多个活动实例的。为了让某个活动在整个应用程序的上下文中只存在一个实例就要借助 singleTask 模式来实现了。当活动的启动模式指定为 singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。



修改后的代码如上面所示,FirstActivity会启动SecondActivity,SecondActivity会启动FirstActivity,看将启动模式变更为singleTask之后两个活动之间是调用的onCreate方法重新实例化一个返回栈对象,还是调用onRestart方法重新调回之前的一个对象,打印出的log如下图

可以发现从SecondActivity启动FirstActivity时调用的是onRestart方法,并且把SecondActivity这个返回栈对象destory掉了,重复操作,打印的log是相同的。说明singleTask模式在每次启动该活动时,系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例(onRestart),并把在这个活动之上的所有活动统统出栈(SecondActivity的onDestory方法),如果没有发现就会创建一个新的活动实例(重新调用了SecondActivity的onCreate方法)。

singleInstance
不同于以上 3 种启动模式,指定为 singleInstance 模式的活动会启用一个新的返回栈,在每一次启动页面的时候会调用这个回栈来管理这个活动(其实如果 singleTask 模式指定了不同taskAffinity,也会启动一个新的返回栈来管理这个活动(其实如果 singleTask 模式指定了不同的 taskAffinity,也会启动一个新的返回栈)。那么这样做有什么意义呢?想象以下场景,假设我们的程序中有一个活动是允许其他程序调用的,如果我们想实现其他程序和我们的程序可以共享这个活动的实例,应该如何实现呢?使用前面 3 种启动模式肯定是做不到的,因为每个应用程序都会有自己的返回栈,同一个活动在不同的返回栈中入栈时必然是创建了新的实例。而使用 singleInstance 模式就可以解决这个问题,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实例的问题。下面是demo代码




FirstActivity启动SecondActivity,SecondActivity启动ThirdActivity。在SecondActivity的启动模式中设置为singleInstance。log的打印情况如下

FirstActivity的Task_ID和ThirdActivity的Task_ID是一致的。这说明SecondActivity的返回栈不同于另外两个,它单独存放在一个返回栈中。按下一次返回键

页面直接回到了FirstActivity的页面。再按返回键,回到了SecondActivity的页面再按返回,则会退出程序。
原理呢:由于 FirstActivity 和 ThirdActivity 是存放在同一个返回栈里的,当在 ThirdActivity的界面按下 Back 键,ThirdActivity 会从返回栈中出栈,那么 FirstActivity 就成为了栈顶活动显示在界面上,因此也就出现了从 ThirdActivity 直接返回到 FirstActivity 的情况。然后在FirstActivity 界面再次按下 Back 键,这时当前的返回栈已经空了,于是就显示了另一个返回栈的栈顶活动,即 SecondActivity。最后再次按下 Back 键,这时所有返回栈都已经空了,也就自然退出了程序。这样就可以实现我们日常使用的app中非正常页面跳转了。

就先写到这里吧~
网友评论