殺不掉的知乎 - 聊一聊 Android 的多任務

保活在 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。

這也是爲什麼知乎首次啓動是正常的,用着用着纔可能出現這種情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章