被後臺殺死後,Android應用如何從新走閃屏邏輯

Android應用運行在後臺的時候,常常被系統的LowMemoryKiller殺掉,當用戶再次點擊icon或者從最近的任務列表啓動的時候,進程會被重建,而且恢復被殺以前的現場。什麼意思呢?假如APP在被殺以前的Activity堆棧是這樣的,A<B<C,C位於最上層ide

後臺殺死與恢復的堆棧.jpg

APP被後臺殺死後,APP端進程被銷燬了,也就不存在什麼Activity了,也就沒有什麼Activity堆棧,不過AMS的倒是被保留了下來:函數

後臺殺死與恢復的堆棧-殺後.jpg

當用戶再次啓動APP時候會怎麼樣呢?這個時候,首先看到其實C,而不是棧底部的A,也就是說每每被殺死後,恢復看到的第一個界面是用戶最後見到的那個界面。this

後臺殺死與恢復的堆棧-恢復.jpg

而用戶點擊返回,看到的就是上一個界面B,其次是Aspa

後臺殺死與恢復的堆棧-恢復b.jpg

之因此這樣是由於APP端Activity的建立其實都是由AMS管理的,AMS嚴格維護這APP端Activity對應的ActivityRecord棧,能夠看作當前APP的場景,不過,APP端Activity的銷燬同AMS端ActivityRecord的銷燬並不必定是同步的,最明顯的就是後臺殺死這種場景。Android爲了可以讓用戶無感知後臺殺死,就作了這種恢復邏輯,不過,在開發中,這種邏輯帶了的問題確實多種多樣,甚至有些產品就不但願走恢復流程,本文就說說如何避免走恢復流程。結合常見的開發場景,這裏分爲兩種,一種是針對推送喚起APP,一種是針對從最近任務列表喚起APP(或者icon)。code

從最近的任務列表喚起,不走恢復流程

首先,APP端必須知道當前Activity的啓動是否是在走恢復流程,Activity有一個onCreate方法,在ActivityThread新建Activity以後,會回調該函數,若是是從後臺殺死恢復來的,回調onCreate的時候會傳遞一個非空的Bundle savedInstanceState給當前Activity,只要判斷這個非空就能知道是不是恢復流程。router

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
   }
複製代碼

知道恢復流程以後,如何處理呢?其實很簡單,直接吊起閃屏頁就能夠了,不過這裏有一點要注意的是,在啓動閃屏頁面的時候,必需要設置其IntentFlag:Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK,這樣作的理由是爲了清理以前的場景,否則以前的ActivityRecord棧仍然保留在ActivityManagerService中,具體實現以下,放在BaseActivity中就能夠:cdn

Intent intent = new Intent(this, SplashActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
複製代碼

若是不設置會怎麼樣呢?舉個例子,最多見的就是閃屏以後跳轉主界面,主界面常常有router邏輯,而且其啓動模式通常都是singleTask,處理一些推送,因此其onCreate跟onNewIntent都有相應的處理,若是不設置,在閃屏結束後,在startActivity啓動主界面的時候,實際上是先走恢復邏輯,而後走singleTask的onNewIntent邏輯,也就是說,onNewIntent跟onCreate是會同時調用的,也可能就會引起重複處理的邏輯,所以最好清理乾淨。blog

從推送喚起被殺APP時,如何走閃屏邏輯

對於推送消息的處理,其路由器通常放在MainActivity,而且在onCreate跟onNewIntent都有添加,若是APP存活的狀況,能夠直接跳轉目標頁面,若是APP被殺,這個時候,但願先跳轉主界面,再跳轉目標頁面,在效果上來看就是,用戶先看到目標頁面,點擊返回的時候再看到主界面,若是加上閃屏,但願達到的效果是先看到閃屏、點擊返回看到目標頁,再點擊返回看到主頁面。若是簡單劃分一下推送場景,能夠看作一下三種進程

  • 進程存活,Activity存活
  • 進程存活,可是沒有Activity存活
  • 進程不存在(不管是否被殺)

其實後面兩種徹底能夠看作一種,這個時候,都是要先start MainActivity,而後讓MainActivity在其OnCreate中經過startActivityForResult啓動SplashActivity,SplashActivity返回後,在start TargetActivity。下面的討論都是針對後面兩種,須要作的有兩件事路由

  • 一是:檢測出後面兩種場景,而且在喚起主界面的時候須要添加Intent.FLAG_ACTIVITY_CLEAR_TASK清理以前的現場
  • 二是:在MainActivity的路由系統中,針對這兩種場景要,先跳轉閃屏,閃屏回來後,再跳轉推送頁

如何判斷呢,後面兩種場景其實只須要判斷是否有Activity存活便可,也就是查查APP的topActivity是否爲null,注意不要去向AMS查詢,而是在本地進程中查詢,能夠經過反射查詢ActivityThread的mActivities,也能夠根據本身維護的Activity堆棧來判斷,判斷沒有存活Activity的前提下,就跳轉主頁面去路由

Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setDate(跳轉的Uri scheme)
startActivity(intent);
複製代碼

在MainActivity的路由中,須要準確區分是不是推送跳轉進來的,若是不是推送跳轉進來,就不須要什麼特殊處理,若是是推送跳轉進來必定會攜帶跳轉scheme數據,根據是否攜帶數據作區分便可,看一下MainActivity的代碼:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Uri uri= getIntent().getData();
    <!--只有在intent被設置了跳轉數據的時候纔去跳轉,通常是推送就來,若是冷啓動,是沒有數據的-->
    if(uri!=null){
        SplashActivity.startActivityForResult(this,JUMP_TO_TARGET)
    }
}
<!--Intent.FLAG_ACTIVITY_CLEAR_TASK保證了onNewIntent被調用的時候,進程必定是正常活着的-->
@Override
protected void onNewIntent(Intent intent) {
    Uri uri= intent.getData();
    intent.setData(null);
    router(uri);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode==JUMP_TO_TARGET && requestCode == RESULT_OK){
        router(getIntent().getData());
        getIntent().setData(null);
    }
}

private void router(Uri uri) {

}
複製代碼

經過上面兩部分的處理,基本可以知足APP「死亡」的狀況下,先跳轉閃屏的需求。

做者:看書的小蝸牛 原文連接:被後臺殺死後,Android應用如何從新走閃屏邏輯

僅供參考,歡迎指正

相關文章
相關標籤/搜索