Activity生命週期
1:activity四種啟動方式
standard,SingleTask,SingleTop,SingleInstance
standard:是系統預設的,每次啟動該activity都會建立一個例項放在返回棧中,並且置於棧頂。
SingleTop:在每次啟動活動的時候如果發現棧的棧頂已經有該活動了,那麼就直接使用它,不會再建立新的活動例項。如果啟動的時候沒有在棧頂,那麼還是會建立一個新的例項,比如說A->B ,返回棧存放過程是建立A,建立B,然後B->A(並非通過back回到A),建立A例項,因為此時返回棧中棧頂是B,所以會建立A例項。
SingleTask:整個返回棧中只有一個例項。每次啟動的時候,就會在返回棧中檢查是否有例項,如果有例項但不在棧頂,那麼就會讓棧頂出棧,它稱為棧頂。例子:A->B,建立A例項,建立B例項,從B->A,此時返回棧中有A例項,就會讓B例項出棧,此時棧中只有A的例項,所以點選Back後就會退出程式。(只要是在A上的例項全部出棧,如ABCD,需要用到B,此時棧中AB,CD出棧)
SingleInstance:對於設定該模式的活動(Activity),會建立一個例項儲存在新的返回棧中,這是因為可供其他的程式呼叫這個活動,達到了共享這個例項,在單個程式中如:A->B(模式SingleInstance)->C,建立A例項,建立B例項(新返回棧中),建立C例項,當點選back鍵時,會C彈出棧,顯示A,再次點選back鍵,A彈出棧,顯示B。原因是A和C在一個返回棧中,而B在一個新的返回棧中。
2:Activity正確使用
在實際開發中,頁面很多,activity很多,所以,想要通過執行程式來判斷當前所看的頁面是對應哪一個activity就要建立一個父類activity,這樣的話,讓他們都來繼承這個父類,在父類中通過OnCreate方法來執行一些公用的程式碼和Log日誌即可。主要BaseActivity不需要在清單中註冊。
所有繼承該父類的activity都要呼叫一個父類的onCreate方法。
public class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e("BaseActivity",getClass().getSimpleName()); } }
3:Activity隨時隨地都可以退出
一個程式中有退出登入,這個時候就要保所有的activity,然後可以銷燬所有的activity並且之後跳轉到登入頁面,如果想要退出到桌面,也可以加入殺死程式的程式碼,防止該程式程式在後臺一直執行。
殺死程式程式碼
android.os.Process.killProcess(Process.myPid());//獲取id,殺死當前id,並殺死當前程式,不可殺死其他程式程式
Activity管理類
public class ActivityCollector { public static List<Activity> listActivity = new ArrayList<>(); /** * 新增活動 * */ public static void addActivity(Activity activity){ listActivity.add(activity); } /*刪除活動*/ public static void removeActivity(Activity activity){ listActivity.remove(activity); } /*銷燬所有活動*/ public static void finishAllActivity(){ for (Activity activity:listActivity) { if(!activity.isFinishing()){ activity.finish(); } } } }
4:啟動Activity最佳寫法
問題:假設兩個Activity,FirstActivity和SecondActivity,第二個活動不是你寫的,但是你需要跳轉到該頁面,同時需要傳一些引數,此時,你可以問你同事需要傳什麼引數,或者自己去看需要什麼引數,這樣太麻煩。這時就需要優化程式碼,你同事可以在第二個介面就留一個方法入口,把需要的引數都列出來,你只需要用類名.方法名即可
該方法寫在第二個活動裡,也就是需要跳轉到的頁面。
/*啟動最佳寫法*/ public static void actionStart(Context context,String param1,String param2){ Intent intent = new Intent(context,MainActivity2.class); intent.putExtra("param1",param1); intent.putExtra("param2",param2); context.startActivity(intent); }
在MAinActivity1裡呼叫。
MainActivity2.actionStart(this,"ceshi1","ceshi2");
5:生命週期以外的方法
- onSaveInstanceState()
- onRestoreInstanceState()
onSaveInstanceState()和onRestoreInstanceState()使用詳解
注意
1、如果是使用者自動按下返回鍵,或程式呼叫finish()退出程式,是不會觸發onSaveInstanceState()和onRestoreInstanceState()的。2、每次使用者旋轉螢幕時,您的Activity將被破壞並重新建立。當螢幕改變方向時,系統會破壞並重新建立前臺Activity,因為螢幕配置已更改,您的Activity可能需要載入替代資源(例如佈局)。即會執行onSaveInstanceState()和onRestoreInstanceState()的。
- 1.配置改變導致Activity被殺死,橫屏變豎屏:在onStop之前會呼叫onSaveInstanceState()儲存資料在重建Activity之後,會在onStart()之後呼叫onRestoreInstanceState(),並把儲存下來的Bundle傳給onCreate()和它會預設重建Activity當前的檢視,我們可以在onCreate()中,回覆自己的資料。
- 2.記憶體不足殺掉Activity,優先順序分別是:前臺可見,可見非前臺,後臺。
在stop()之前系統會呼叫onSaveInstanceState()方法,以便您的Activity可以使用一組鍵值對來儲存狀態資訊。此方法的預設實現儲存有關Activity檢視層次結構狀態的資訊,例如EditText小部件中的文字或ListView的滾動位置。
static final String STATE_SCORE = "playerScore"; static final String STATE_LEVEL = "playerLevel"; ... @Override public void onSaveInstanceState(Bundle savedInstanceState) { // 儲存使用者自定義的狀態 savedInstanceState.putInt(STATE_SCORE, mCurrentScore); savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel); // 呼叫父類交給系統處理,這樣系統能儲存檢視層次結構狀態 super.onSaveInstanceState(savedInstanceState); }
恢復您的Activity狀態
當您的Activity在之前被破壞後重新建立時,您可以從Bundle系統通過您的Activity中恢復您的儲存狀態。這兩個方法onCreate()和onRestoreInstanceState()回撥方法都會收到Bundle包含例項狀態資訊的相同方法。因為onCreate()呼叫該方法是系統正在建立一個新的Activity例項或重新建立一個以前的例項,所以您必須Bundle在嘗試讀取之前檢查該狀態是否為空。如果它為空,那麼系統正在建立一個Activity的新例項,而不是恢復之前被銷燬的例項。
例如,下面是如何恢復一些狀態資料onCreate():
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 記得總是呼叫父類 // 檢查是否正在重新建立一個以前銷燬的例項 if (savedInstanceState != null) { // 從已儲存狀態恢復成員的值 mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); } else { // 可能初始化一個新例項的預設值的成員 } ... }
onCreate()您可以選擇執行onRestoreInstanceState(),而不是在系統呼叫onStart()方法之後恢復狀態。系統onRestoreInstanceState()只有在存在儲存狀態的情況下才會恢復,因此您不需要檢查是否Bundle為空:
public void onRestoreInstanceState(Bundle savedInstanceState) { // 總是呼叫超類,以便它可以恢復檢視層次超級 super.onRestoreInstanceState(savedInstanceState); // 從已儲存的例項中恢復狀態成員 mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); }
6:onNewIntent()方法
該方法和啟動模式緊密相關前提:ActivityA已經啟動過,處於當前應用的Activity任務棧中;
當ActivityA的LaunchMode為Standard時:
由於每次啟動ActivityA都是啟動新的例項,和原來啟動的沒關係,所以不會呼叫原來ActivityA的onNewIntent方法
當ActivityA的LaunchMode為SingleTop時:
如果ActivityA在棧頂,且現在要再啟動ActivityA,這時會呼叫onNewIntent()方法 ,生命週期順序為:
onCreate--->onStart--->onResume---onPause>onNewIntent--->onResume
當ActivityA的LaunchMode為SingleInstance,SingleTask:
如果ActivityA已經在堆疊中,那麼此時會呼叫onNewIntent()方法,生命週期呼叫順序為:
onCreate--->onStart--->onResume---按下Home鍵>onPause--->onstop--->onNewIntent--->onRestart--->onstart--->onResume
注意:在記憶體吃緊的情況下,系統可能會kill掉後臺執行的 Activity ,如果不巧要啟動的那個activity例項被系統kill了,那麼系統就會呼叫 onCreate 方法,而不呼叫 onNewIntent 方法。這裡有個解決方法就是在 onCreate 和 onNewIntent 方法中呼叫同一個處理資料的方法,
總結:在activityA中設定了對應的啟動模式後,其他(自己也行)activityB往A中使用intent跳轉,攜帶值時就會呼叫onNewIntent()方法,然後是onRestart->onStart()->onResume();
7:Activity的啟動過程
啟動過程不是啟動模式,所謂啟動過程,就是從你看到應用圖示點選後到正式開啟所經過的過程
- 第一種是從桌面launcher上點選相應的應用圖示
- 第二種是在activity中通過呼叫startActivity來啟動一個新的activity
由於launcher也是一個程式,所以當我們點選應用圖示的時候系統會呼叫startActivitySately()。(具體在第二篇作答)
8:Activity和fragment繫結後流程
fragment存在被activity動態載入和靜態載入,靜態載入實在xml檔案中載入,