Activity的启动模式

来源:互联网 发布:沈飞 成飞 知乎 编辑:程序博客网 时间:2024/05/22 03:22

最近在看《Android开发艺术探索》一书,准备把里面的东西敲一遍,顺便记录成博客,日后方便查看。好了现在开始~~~


LaunchMode

在默认情况下(默认启动模式),多次启动同一个Activity的时候,系统会根据你启动的次数来创建相同数量的Activity实例,并把他们一一放入任务栈中,当逐次按下back键,这些Activity实例会一一回退。任务栈是一个“后进先出”的栈结构,按back的时候直至栈空,系统会回收这个任务栈。Android启动模式不单单是默认一种,有standard、singleTop、singleTask、和singleInstance四种。

standard模式

standard模式即为标准模式,也是默认模式。这种模式下每次启动一个Activity就会创建一个新的实例,不管这个实例是否已经存在。被创建的实例的生命周期符合典型情况下Activity的生命周期,即onCreate、onStart、onResume方法都会被调用。
一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。
比如Activity A启动了Activity B(B是标准模式),那么B就会进入到A所在的栈中。
注意:当用ApplicationContext去启动标准模式下的Activity的时候会报错。简单的代码如下:

findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent  intent = new Intent();                intent.setClass(MainActivity.this,SecondActivity.class);                //用Context类型去启动默认模式下的SecondActivity                getApplicationContext().startActivity(intent);            }        });

会报如下错误:

FATAL EXCEPTION: main11-30 08:41:19.070 4104-4104/com.example.pan.myapplication E/AndroidRuntime: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

原因是因为非Activity类型的Context并没有所谓的任务栈,所以就会有这个问题,解决这个问题的方法是—为待启动的Activity指定 FLAG_ACTIVITY_NEW_TASK 标记位,这样启动的时候就会为它创建一个新的任务栈,这个时候待启动的Activity实际上是以singleTask模式启动的。添加代码如下:

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

singleTop模式

singleTop为栈顶复用模式,在这种模式下,如果新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的 onNewIntent 方法会被回调,通过此方法的参数我们可以取出当前请求的信息。
举例代码如下,SecondActivity:

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent intent = new Intent();                intent.setClass(SecondActivity.this, SecondActivity.class);                intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);                intent.putExtra("testMsg", "Hello,This is my test message!");                startActivity(intent);            }        });    }    @Override    protected void onNewIntent(Intent intent) {        super.onNewIntent(intent);        String testMsg = intent.getStringExtra("testMsg");        Toast.makeText(this, "testMsg:" + testMsg, Toast.LENGTH_LONG).show();    }

在启动了SecondActivity之后,点击restart SecondActivity按钮,得到的结果如图:
这里写图片描述

从结果中可以看到,在singleTop模式下第二次启动SecondActivity会调用它的onNewIntent 方法,请求的信息可以通过参数Intent来获取。

注意:这个Activity的onCreate、onStart不会被系统调用,因为它们并没有发生改变。
在SecondActivity的onCreate、onStart、onResume方法中添加打印日志,运行SecondActivity并连续点击restate SecondActivity按钮,由下图可以看出,只会执行onResume方法,而onCreate、onStart不会执行(第一次启动的时候会调用的)。
这里写图片描述

如果新Activity的实例已经存在但是不在栈顶,那么新Activity仍然会被重新创建。

singleTask模式

singleTask模式,也叫做栈内复用模式。这是一种单实例模式,顾名思义,只要Activity在一个栈中存在,那么多次启动该Activity都不会再重新创建实例,同时会调用其onNewIntent 方法。具体一点,当一个具有singleTask模式的Activity请求启动后,比如Activity A,系统首先会寻找是否存在A想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例后把A放到栈中。如果存在A所需的任务栈,这时要看A是否在栈中已经有实例,如有则系统会把A调到栈顶并调用它的onNewIntent 方法,如果实例不存在,则创建A的实例并压入栈。

  • 情况1:比如目前任务栈S1中的情况为ABC,这个时候Activity D以singleTask模式请求启动,其所需要的栈为S2,由于S2和D的实例都不存在,则系统会创建S2,再将创建的D的实例放到S2
    这里写图片描述

  • 情况2:假设D所需的任务栈为S1,其他情况如情况1,那么由于S1已经存在,那么系统会直接创建D的实例并将其放入S1
    这里写图片描述

  • 情况3:D所需的任务栈为S1,并且当前任务栈S1的情况为ADBC,根据栈内复用的原则,此时D不会重新创建,系统会把D切换到栈顶并调用其onNewIntent 方法,同时由于singleTask默认具有clearTop的效果,会导致栈内所有在D上面的Activity全部出栈,于是S1中的情况为AD
    这里写图片描述

singleInstance模式

singleInstance模式,又叫单实例模式,它是一种加强版的singleTask模式,所以除了具备singleTask的所有特性外,它只能单独地位于一个任务栈中 。换句话说Activity A是单实例模式,当A启动后,系统会为它创建一个新的任务栈,由于A具有单实例的特性,故而之后在该栈中有且只有这个实例。这个就不会举例了。

到这里,四个模式已经讲的差不多了(基本套用书上的东西),其中出现的频率很高的是“任务栈”一词,后续将会对它做一个深入较为的了解……

0 0