Activity之task-----by 安仔

本文深入探讨Android中Activity的四种启动模式:standard、singleTop、singleTask及singleInstance,通过实例演示每种模式如何影响Activity在任务栈中的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.基础辅助命令
在这之前需要学会一个adb命令,如下:abd shell dumpsys activity
这个命令用于打印出当前手机之中的activity中的信息。打开命令行窗口,然后进入adb对应的目录下。如下截图:
这里写图片描述
键入如下命令:
这里写图片描述
因为打印的目录较多,所以将输出信息保存到一个文件中,如下截图:
这里写图片描述
我们将activity中的信息输出到了d盘的activities.txt文件中。因文件中内容太多,所以直接找到我们需要的东西——activity堆栈信息,查找关键字:ACTIVITY MANAGER ACTIVITIES,可看到如下所示的结果:
这里写图片描述
可看到红色的Task关键字,这个关键字,为保存一些列的activity,在系统中用TaskRecord来代表
蓝色的关键字,就为相应的activity,他被Task用ActivityRecord来代表并保存
也可看到Task上面是Stack,Stack上面是Display,因本节讲述Activity的Task,故不对此作讨论。(注意,#号后面的东西只是一个数字序列,比如第一个Task id #4194可以这样认为,Task的id号为4191)有了上面的基础命令之后,我们接下来进入正题Activity的Task。
二.为什么要有Task?
在以往的应用开发中,要开发一个应用,采用建立新的进程或者新的线程来实现。但是这些进程之间如果要共享,就变得非常麻烦。Android弱化了进程的概念,强化了组件的概念。就我个人而言,这种转变实在是进步之举,当然也给我深入学习系统,带来了很大的麻烦。Android中各个组件各司其职,一个应用有很多组件组成,但是这些应用可以不用完成所有的组件,为什么?因为系统已经做好一部分的组件了,我们的应用只需要调用这些组件即可。比如,你想选择图片,我们不用自己去写一个activity,然后设定布局,然后加载图片在布局上,然后再设计手指点了某张图片之后的逻辑。我们只需要,打开系统自带的组件就好了,上面的这一些列步骤已经被系统实现了。那么问题就出现在了打开系统自带的图片选择界面之后,如果我们按返回键,系统该如何反应?正常逻辑应该是回到应用中(即打开这个图片选择界面的应用)。如果我们再考虑深一点,我们在图片选择界面点击了编辑图片的按钮,这个按钮会去打开一个图片编辑的应用相应的activity,我们编辑完成之后,点击保存,弹出让你选择保存在内部存储,还是外部存储,你选择的存储界面它又打开的是文件管理器的应用相应的activity。好了一切做好了,这回,你点击返回键,应该按照前面的步骤一步一步的返回才是。
但是,android虽然弱化进程的概念,但是毕竟不能丢掉进程,因为他的内核是Linux。既然上面这些图片选择器,存储选择界面,图片编辑界面都是不同的应用,那么这些都应该是在不同的进程中的,我们按返回键,还得判定从一个进程返回到另外一个进程。为了保存这些被打开的组件的信息,android使用了Task对这些activity进行管理。Task是一种具有先进后出的特性,类似于堆栈,打开一个新的应用,系统就会创建与之对应的Task,用来保存相应的activity信息
三.Activity的四种启动模式
1.standard
2.singleTop
3.singleTask
4.singleInstance
这四种启动模式在activity的属性android:launchMode中指定。正是这种启动的模式决定了activity在Task中的顺序
第一种,standard模式,
这种模式,只要你打开一个activity,那么这个activity就会被创建然后加入Task中。做个实验,编写如下代码:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void standard(View v){
        Intent intent = new Intent(this,MainActivity.class);
        startActivity(intent);
    }
}

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity"
        android:launchMode="standard">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

standard函数为一个Button被点击之后执行的函数,我们设置MainActivity的启动模式为standard,多次点击这个Button ,将会在Task中创建多个Activity。我们点击三下activity,然后导出activity堆栈信息进行查看。截图如下:
这里写图片描述

这里写图片描述

Task id #4199就是我们创建的这个应用对应的Task。它里面保存有三个ActivityRecord.三个都是MainActivity。可见standard的开启模式为:创建一个activity并加入对应的Task中。创建activity时调用activity对应的生命周期函数,如onCreate,onResume等等。
第二种,singleTop模式。
我们将上面的android:launchMode 换成singleTop,试一试,然后点击三次,看看什么情况。截图如下:
这里写图片描述

不管我点击多少次,它都只有一个activity的实例对象。如果这个MainActivity的前面有一个activity,该会是什么样子的呢。继续实验:
写一个activity,并让他在MainActivity的前面。然后再次启动这个MainActivity。那么MainActivity还会是一个吗?相应的代码再此处省略掉,毕竟能看到这篇文章的人,绝非初学者。直接上我们导出的activity堆栈信息。如下图:
这里写图片描述

可以看到最底层为一个MainActivity,中间有一个SingleTopActivity,然后最上面有一个MainActivity。 那么这个SingleTop的启动模式的逻辑就是:当需要启动的activity位于Task的顶部时,则不会创建一个新的实例,直接使用这个activity实例;如果activity不在Task的顶部,则会创建一个新的实例,然后加入Task中,不管以前是否已经创建过activity实例。
这里可能会有疑问,我们创建新的Activity会调用相应的生命周期函数。如果是一个位于Task顶部的Activity,并且该Activity的launchMode为single Top,它会怎么做呢?答案是:会去调用该activity的onNewIntent()方法。我们补充一下上面的结论:
“当需要启动的activity位于Task的顶部时,则不会创建一个新的实例,直接使用这个activity实例,并调用这个activity的onNewIntent()方法;如果activity不在Task的顶部,则会创建一个新的实例,然后加入Task中,不管以前是否已经创建过activity实例。
第三种。singleTask模式。
直接给出结论,然后实验,结论如下:
SingleTask模式的activity具有系统的唯一性,(指一个系统只有一个该activity实例),如果系统中已经存在了该activity实例,找到这个activity对应的Task,然后将这个activity上面的所有activitiy都删掉,并调用这个activity的onNewIntent()方法。如果系统中不存在这个activity实例。那么回去创建一个activity实例,然后加入对应的Task中。
下面的截图为MainActivity被设置为singleTask,并且它的上面还有一个singleTaskActivity。
这里写图片描述
我们现在从SingleTaskActivity中再次启动MainActivity得如下结果:
这里写图片描述
只有MainActivity一个activity,再它上面的activity被删除了。
再考虑如下情况,既然具有系统唯一性,那么我从另外一个应用中启动这个MainActivity将会怎样呢?
我们再写另外一个程序。用来启动上面程序的MainActivity,当然我们也让这个MainActivity上面同样有SingleTaskActivity。为了能让其他进程打开这个MainActivity,我们通过IntentFilter来实现,我们给这个MainActivity设定一个action叫做singletask.代码部分如下:

<activity android:name=".MainActivity"
    android:launchMode="singleTask"
    android:excludeFromRecents="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <action android:name="singletask"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

我们写另外一个应用,叫做TaskTest,他的主activity叫做SingleTasTesActivity,启动MainActivity 的代码如下

Intent intent = new Intent();
intent.setAction("singletask");
startActivity(intent);

我们先打开MainActivity,然后在MainActivity上面放一个SingleTaskactivity,然后按home键,进入系统主界面,启动另外一个应用TaskTest。得到如下的堆栈信息:
这里写图片描述

绿色为我们写的测试程序TaskTest,主Activity 叫做SingleTaskTestActivity .我们可以观察到此时系统,已经打开了一个MainActivity,并且在MainActivity的上面有一个SingleTaskActivity,见红色部分。并且可以观察到红色和绿色所在的Task id并不相同,因为他们两个在不同的应用程序中。
我们现在点击TaskTest应用的按钮,来打开MainActivity,(记住这个MainActivity的启动模式为singleTask),看看此时Task中的activity该如何变化。对的如下的堆栈信息:
这里写图片描述
观察到Task id#4221跑到了最上面,Task id #4222则在下面,对比上图,此时系统并没有去创建一个新的Task去存储MainActivity,而是使用了原来就已经存在MainActivity的Task。并且,你也会发现MainActivity上面的singleTaskActivity被删除了。MainActivity具有系统唯一性。 此时,如果MainActivity下面还有Activity的话,此时,按返回键将不会回到TaskTest应用中,而是会回到MainActivity下面的那个activity对应的应用。这里就需要注意,因为,这是一个bug,并且此种,bug,对于初级程序员来说,可能觉得是系统的,“怎么我从TaskTest打开一个activity之后,按返回键,返回的却不是TaskTest应用,一定是系统出毛病了,狗日的公司,不买个好点的手机”
第四种,singleInstance模式
先给出结论,然后再做实验:
SingleInstance具有系统的唯一性(系统只有一个实例),同时该activity在一个单独的Task,且该Task只有一个activity。 我们给上面的MainActivity设置为singleInstance,然后在MainActivity中启动自己,看看效果,发现Task中只有一个activity。验证信息,因为过于简单,这里就不贴出来了。
我们考虑一下,如果MainActivity上面还有一个activity ,然后从这个activity中启动MainActivity,会是什么情况。我们做个实验。
我们发现,从MainActivity中启动一个其他的activity,MainActivity单独占一个Task,其他的Activity在另外的Task中,如下图:
这里写图片描述
可一看见MainActivity单独占一个Task,而从MainActivity 启动的SigleTaskActivity在另外一个Task中。如果我们再次从SingleTaskActivity中启动MainActivity会是什么样呢?继续做实验,结果如下图:
这里写图片描述

可以发现,MainActivity并没有再次创建实例,而是使用了原来就已经创建的实例。
同理,从另外一个应用中启动这个MainActivity也会是同样的效果,此处就不做过多的实验。
希望,上面的实验对相应的人员有所帮助,凡是不懂,或不明白者,皆可按,本文第一小节介绍的基础辅助命令进行一一验证。
下一小节将介绍activity的taskAffinity属性,和process属性。


wwwwwwwwww

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值