美文网首页Android开发Android开发经验谈Android技术知识
杀不掉的知乎 - 聊一聊 Android 的多任务

杀不掉的知乎 - 聊一聊 Android 的多任务

作者: 4f28c8f381a4 | 来源:发表于2020-03-26 14:44 被阅读0次

    保活在 Android 绕不开的话题,有些 APP 为了保活煞费苦心。近来发现打开知乎,在近期任务却看不到知乎,知乎是怎么做到这么强悍的。下面分享来自 NanBox 博客,来揭开知乎是如何做到在近期任务完美隐藏的:

    不知道大家平时使用 APP 的时候,有没有碰到过下面这种情况:

    这是我在最近使用知乎的时候出现的,可以看到在任务列表里面看不到知乎,但很明显它还在运行中。你现在打开知乎看大概率是正常的,原因后面会提到。

    通常要杀掉一个 APP 的进程,最直接的方法的就是在任务列表里把对应的任务划掉。于是,保活黑科技又增加了一种新思路:如果在任务列表里把应用隐藏掉 ,那用户不就杀不掉了?

    事先说明一下,本文并不是教大家怎么做保活,仅探讨这是怎么做的,并借此聊一聊 Android 的多任务。而且对于这样的体验,我是真的被恶心到了。

    怎么杀掉它?

    任务列表并不是杀掉 APP 的唯一途径,我们先看看要怎样才能杀掉这种应用。

    adb

    我们可以通过 adb shell ps 查看系统当前运行的所有进程,和预期的一样,在里面找到了还在运行中的知乎:

    然后可以使用 adb shell am force-stop com.zhihu.android 强制杀掉知乎进程。

    系统设置

    对于普通用户,也还是有办法的。进入系统设置,在应用设置里找到知乎,点击强行停止:

    但无论是哪种方法,都是比较麻烦的,真心希望大家不要这样搞。

    excludeFromRecents

    其实,Android 是允许我们在任务列表里隐藏的,而且很简单,只要在清单中声明了android:excludeFromRecents="true" 就好了。

    我们新建一个项目试一下,把 MainActivity 加上这个配置:

    <activity
        android: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,清单配置如下:

    <activity
        android: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>
    
    <activity
        android:name=".SecondActivity"
        android:label="Task 2"
        android:launchMode="singleTask"
        android:taskAffinity="com.nanbox.task2" />
    

    当两个 Activity 都开启后,任务列表就会出现两个任务。

    taskAffinity 经常会和 singleTask 搭配使用,当启动一个 singleTask 的 Activity 时,系统会先比对当前的和新的 taskAffinity,如果不一致就会在一个新的 Task 里启动 Activity。

    另外,不仅一个应用可以有多个任务,不同应用也可以属于同一个任务,任务是可以跨进程的。这种使用场景应该比较少,这里就不展开讲了。

    骚操作

    基于上面的多任务,假如我们一个应用有两个任务,一个可见一个不可见,用户只能在任务列表里杀掉可见的任务,不可见的任务还可以继续跑,那岂不是可以一定程度上保活?

    我们来试一下,还是上面的代码,不过这次让 Task 2 在任务列表中不可见:

    <activity
        android: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>
    
    <activity
        android: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();
    }
    

    于是就有了这种效果:

    GIF 重复播放不太好体现效果,感兴趣的可以自己跑一下看看。

    首次启动可以在任务列表中看到 Task1,当启动 Task2 并结束 Task1 之后,任务列表就变成空了,但点击桌面应用可以恢复到正在运行的 Task2。

    这也是为什么知乎首次启动是正常的,用着用着才可能出现这种情况。

    相关文章

      网友评论

        本文标题:杀不掉的知乎 - 聊一聊 Android 的多任务

        本文链接:https://www.haomeiwen.com/subject/kbkcuhtx.html