作者:NanBox
, 链接:https://juejin.im/post/5e7b2d07e51d4565b778647f
不知道大家平时使用 APP 的时候,有没有碰到过下面这种情况:
![632b7976069871a98a30434e3eaa18a0.gif](https://i-blog.csdnimg.cn/blog_migrate/4d389dd830825262c01124788c1380d7.gif)
这是我在最近使用知乎的时候出现的,可以看到在任务列表里面看不到知乎,但很明显它还在运行中。你现在打开知乎看大概率是正常的,原因后面会提到。通常要杀掉一个 APP 的进程,最直接的方法的就是在任务列表里把对应的任务划掉。于是,保活黑科技又增加了一种新思路:如果在任务列表里把应用隐藏掉 ,那用户不就杀不掉了?事先说明一下,本文并不是教大家怎么做保活,仅探讨这是怎么做的,并借此聊一聊 Android 的多任务。而且对于这样的体验,我是真的被恶心到了。
![4a58bbc947e724d4fc997c2da492323c.png](https://i-blog.csdnimg.cn/blog_migrate/5f7edc465b20faf5548ebfc51bfc7c0b.jpeg)
怎么杀掉它?
任务列表并不是杀掉 APP 的唯一途径,我们先看看要怎样才能杀掉这种应用。
adb
我们可以通过 adb shell ps
查看系统当前运行的所有进程,和预期的一样,在里面找到了还在运行中的知乎:
![0c927c1e915b038fa3f095adf4a5f090.png](https://i-blog.csdnimg.cn/blog_migrate/38ea314b258318fcb863551029f623a4.jpeg)
然后可以使用 adb shell am force-stop com.zhihu.android
强制杀掉知乎进程。
系统设置
对于普通用户,也还是有办法的。进入系统设置,在应用设置里找到知乎,点击强行停止:
![f3ad3c738e577acc22541088345d034a.png](https://i-blog.csdnimg.cn/blog_migrate/c536d3551c5a86d89baf405c701d4ba7.jpeg)
但无论是哪种方法,都是比较麻烦的,真心希望大家不要这样搞。
excludeFromRecents
其实,Android 是允许我们在任务列表里隐藏的,而且很简单,只要在清单中声明了 andro id:excludeFromRecents="true"
就好了。我们新建一个项目试一下,把 MainActivity
加上这个配置:
<activityandroid:name=".MainActivity"android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
这样就能达到不在任务列表显示的效果。但仅仅如此还达不到知乎的效果,因为首次打开它是有在任务列表显示的。下面引入多任务的另一个概念。
taskAffinity
之所以叫任务列表,是因为这里显示的是当前在执行的任务,而不是当前运行的应用。只不过在默认情况下,一个应用就对应一个任务。每个任务会有一个 TaskAffinity
,可以把它理解为任务名,默认情况下 TaskAffinity
是应用的包名。我们可以用 taskAffinity
属性给 Activity 配置不同的任务名,让一个 APP 拥有多个任务。无论是 excludeFromRecents
还是 taskAffinity
,它们只对栈内的根 Activity
生效,其实它们作用的是任务栈 Task,而不是 Activity。举个例子,我们增加一个 SecondActivity
,清单配置如下:
<activityandroid:name=".MainActivity"android:label="Task 1"android:taskAffinity="com.nanbox.task1">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
<activityandroid:name=".SecondActivity"android:label="Task 2"android:launchMode="singleTask"android:taskAffinity="com.nanbox.task2" />
当两个 Activity 都开启后,任务列表就会出现两个任务。
![aac72acd5eb276fdb4d630434e6c656d.png](https://i-blog.csdnimg.cn/blog_migrate/6264caaf53edfda58b19748252af1e8b.jpeg)
taskAffinity
经常会和 singleTask
搭配使用,当启动一个 singleTask
的 Activity 时,系统会先比对当前的和新的 taskAffinity
,如果不一致就会在一个新的 Task 里启动 Activity。另外,不仅一个应用可以有多个任务,不同应用也可以属于同一个任务,任务是可以跨进程的。这种使用场景应该比较少,这里就不展开讲了。
骚操作
基于上面的多任务,假如我们一个应用有两个任务,一个可见一个不可见,用户只能在任务列表里杀掉可见的任务,不可见的任务还可以继续跑,那岂不是可以一定程度上保活?我们来试一下,还是上面的代码,不过这次让 Task 2 在任务列表中不可见:
<activityandroid:name=".MainActivity"android:label="Task 1"android:taskAffinity="com.nanbox.task1">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
<activityandroid:name=".SecondActivity"android:excludeFromRecents="true"android:label="Task 2"android:launchMode="singleTask"android:taskAffinity="com.nanbox.task2" />
我们把启动过的SecondActivity
存起来,在 MainActivity
中判断,如果 SecondActivity
已经存在就直接启动它,以便恢复到应用上一次的状态:
Activity activity = ActivityProvider.getActivity();
if (activity != null) {
Intent intent = new Intent(this, activity.getClass());
startActivity(intent);
finishAndRemoveTask();
}
于是就有了这种效果:
![0792e04b17a0b09720254e5658462bac.gif](https://i-blog.csdnimg.cn/blog_migrate/48f0ec48b929f9562d743cc49a9f751a.gif)
GIF 重复播放不太好体现效果,感兴趣的可以自己跑一下看看。首次启动可以在任务列表中看到 Task1,当启动 Task2 并结束 Task1 之后,任务列表就变成空了,但点击桌面应用可以恢复到正在运行的 Task2。这也是为什么知乎首次启动是正常的,用着用着才可能出现这种情况。
参考资料
Recents Screen
Activity 清单配置
---END---
![5338a5295ac2006eb16a1782d279c675.png](https://i-blog.csdnimg.cn/blog_migrate/f0c2009c9bc270647e127df8d50aa57d.jpeg)
![5fa40fdc27a739ceea1b880903b08e20.gif](https://i-blog.csdnimg.cn/blog_migrate/a7d86a94282b8b9af02a8d856c78033d.gif)