Android應用運行在後臺的時候,常常被系統的LowMemoryKiller殺掉,當用戶再次點擊icon或者從最近的任務列表啓動的時候,進程會被重建,而且恢復被殺以前的現場。什麼意思呢?假如APP在被殺以前的Activity堆棧是這樣的,A<B<C,C位於最上層ide
APP被後臺殺死後,APP端進程被銷燬了,也就不存在什麼Activity了,也就沒有什麼Activity堆棧,不過AMS的倒是被保留了下來:函數
當用戶再次啓動APP時候會怎麼樣呢?這個時候,首先看到其實C,而不是棧底部的A,也就是說每每被殺死後,恢復看到的第一個界面是用戶最後見到的那個界面。this
而用戶點擊返回,看到的就是上一個界面B,其次是Aspa
之因此這樣是由於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
對於推送消息的處理,其路由器通常放在MainActivity,而且在onCreate跟onNewIntent都有添加,若是APP存活的狀況,能夠直接跳轉目標頁面,若是APP被殺,這個時候,但願先跳轉主界面,再跳轉目標頁面,在效果上來看就是,用戶先看到目標頁面,點擊返回的時候再看到主界面,若是加上閃屏,但願達到的效果是先看到閃屏、點擊返回看到目標頁,再點擊返回看到主頁面。若是簡單劃分一下推送場景,能夠看作一下三種進程
其實後面兩種徹底能夠看作一種,這個時候,都是要先start MainActivity,而後讓MainActivity在其OnCreate中經過startActivityForResult啓動SplashActivity,SplashActivity返回後,在start TargetActivity。下面的討論都是針對後面兩種,須要作的有兩件事路由
如何判斷呢,後面兩種場景其實只須要判斷是否有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應用如何從新走閃屏邏輯
僅供參考,歡迎指正