Xamarin.Android活動的生命週期
一、前言
用過Android手機的人一定會發現一種現象,當你把一個應用置於後臺後,一段時間之後在開啟就會發現應用重新打開了,但是之前的相關的資料卻沒有丟失。可以看出app的“生命”是掌握在系統手上的,而不像Windows上開發的程式。
二、活動的生命週期
這裡我們藉助一張圖幫助我們理解:
當然很多人現在還看不懂這張圖,下面我們會逐一介紹:
1.OnCreate
這個方法是開啟活動後第一個執行的事件,當然也是我們必須重寫的一個方法,其中它大致負責如下的事情:
l 建立檢視
l 初始化變數
l 將靜態變數繫結到列表
OnCreate擁有一個Bundle型別的引數bundle,這個引數至關重要,因為我們知道應用的生命週期不歸自己管,所以就意味隨時可能都會被終止,
所以我們就要能夠儲存這中間使用者操作的資料,並在下次開啟後能夠恢復回去,而這裡的bundle引數就是用來將上一個例項中儲存的資料傳遞進來,
從而恢復使用者上次的狀態。下面的程式碼簡單的演示瞭如何從bundle中獲取資料:
1 protected override void OnCreate(Bundle bundle) 2 { 3 base.OnCreate(bundle); 4 5 string extraString; 6 bool extraBool; 7 8 if (bundle != null) 9 {View Code10 intentString = bundle.GetString("myString"); 11 intentBool = bundle.GetBoolean("myBool"); 12 } 13 SetContentView(Resource.Layout.Main); 14 }
當OnCreate結束後,緊接著執行OnStart方法。
2.OnStart
OnStart將在OnCreate後由系統呼叫,該方法一般只有在需要在檢視出現之前執行特地的任務,比如更新檢視中顯示的值。在該方法完畢之後將執行OnResume方法。
3.OnResume
當活動準備開始與使用者互動時會觸發該方法,一般只會在需要執行以下的操作時才重寫該事件:
l 開始動畫
l 開始監聽GPS更新
l 顯示一些相關的提示和對話方塊
l 註冊廣播監聽
作為演示,下面是初始化照相機的程式碼:
1 public void OnResume() 2 { 3 base.OnResume(); 4 5 if (_camera==null) 6 { 7 // 初始化 8 } 9 }View Code
OnResume非常重要,特別是在觸發OnPause後。使用者又切迴應用,那麼就需要OnResume進行恢復。所以接著就是OnPause事件。
4.OnPause
當活動被切換到後臺時將觸發該方法,一般我們需要在該事件做如下的事情:
l 儲存使用者未提交的資料
l 關閉或清除引用的資源
l 登出廣播
l 如果存在正在顯示的提示或者對話方塊,則必須利用.Dismiss()進行清除。
作為演示,下面的程式碼將把照相機資源進行釋放:
1 public void OnPause() 2 { 3 base.OnPause(); 4 5 if (_camera != null) 6 { 7 _camera.Release(); 8 _camera = null; 9 } 10 }View Code
5.OnStop
當該活動長時間沒有在顯示給使用者下就會觸發,一般會由以下原因觸發:
l 當一個新的活動開啟,並覆蓋該活動時
l 一個已存在的活動切換到前臺時
l 活動被銷燬時
OnStop不是每次都會被執行,如果記憶體低下時,系統將不會執行該事件,而是直接關閉該應用,所以大家在OnPause事件中就要儲存好所以的引數等等。而不能依賴該事件。
6.OnDestroy
該事件是整個活動生命週期中最後一個,但是很多情況下並不會執行到這個事件,所以很少重寫該方法。
7.OnRestart
當用戶通過Home按鈕將該使用者切換到後臺,並在之後又開啟該應用則會觸發該事件。一般也很少重寫該方法。
小節:
通過上面的介紹,我們可以明白活動中不是所有的事件都是有用的,其中比較常用的是OnCreate,OnResume,OnPause當然下面還會介紹專門用來儲存使用者狀態的事件。
三、生命週期中狀態管理
首先我們先用一張圖來形容:
通過這張圖我們可以看出,在應用從恢復到銷燬過程中將會觸發onSaveInstanceState方法,而在應用開啟後則會觸發onRestoreInstanceState方法。下面我們通過一個實際的例子來說明:
我們先通過一個簡單的例子來揭示,如果我們不儲存當前使用者的狀態會出現什麼情況:
首先新建一個Android專案,然後開啟Main.axml,拖拽一個Text(Large),並在下方拖拽一個Button,設定Button的Text為add,然後生成一遍。
開啟MainActivity.cs檔案,並寫入如下程式碼:
1 [Activity(Label = "Activity_Liftcycle", MainLauncher = true, Icon = "@drawable/icon")] 2 public class MainActivity : Activity 3 { 4 int count = 1; 5 6 private TextView tv; 7 8 protected override void OnCreate(Bundle bundle) 9 { 10 base.OnCreate(bundle); 11 SetContentView(Resource.Layout.Main); 12 13 tv = FindViewById<TextView>(Resource.Id.textView1); 14 tv.Text = count.ToString(); 15 Button btn = FindViewById<Button>(Resource.Id.button1); 16 btn.Click += (e, s) => 17 { 18 count++; 19 tv.Text = count.ToString(); 20 }; 21 } 22 }View Code
這裡不用解釋,大家也知道,其實就是一個累加。現在我們F5執行,然後點選幾次Add之後如下所示:
然後我們選擇模擬器,按下 Ctrl + F12 是不是發現模擬機翻轉了,但是你也會發現數字變成了1:
如果你是在使用一個app,翻轉之後出現這個樣子,你一定會非常奇怪。當然你可能會想到使用靜態變數,但是你考慮過一個實際情況沒,
儲存一個還好,如果很多呢。那會消耗更多的記憶體,而且也沒有意義。所以這裡我們就需要重寫上面的OnSaveInstanceState方法,以
便儲存當前使用者的資料,下面將程式碼修改如下:
1 [Activity(Label = "Activity_Liftcycle", MainLauncher = true, Icon = "@drawable/icon")] 2 public class MainActivity : Activity 3 { 4 int count = 1; 5 6 private TextView tv; 7 8 protected override void OnCreate(Bundle bundle) 9 { 10 base.OnCreate(bundle); 11 SetContentView(Resource.Layout.Main); 12 13 //如果存在則恢復之前的狀態 14 if (bundle != null) 15 { 16 count = bundle.GetInt("_count"); 17 } 18 19 tv = FindViewById<TextView>(Resource.Id.textView1); 20 tv.Text = count.ToString(); 21 Button btn = FindViewById<Button>(Resource.Id.button1); 22 btn.Click += (e, s) => 23 { 24 count++; 25 tv.Text = count.ToString(); 26 }; 27 } 28 29 protected override void OnSaveInstanceState(Bundle outState) 30 { 31 base.OnSaveInstanceState(outState); 32 //儲存當前狀態 33 outState.PutInt("_count", count); 34 } 35 }View Code
我們接著點選add:
然後翻轉:
還有一個OnRestoreInstanceState也可以用來恢復狀態,只是它會在OnStart之後執行。意味著它是在所有初始化完成之後進行的,而該方法的引數與OnCreate中的引數是一致的,所以不是常用該方法來恢復狀態。