Android開發入門教程--3.Activity入門指南


Activity是Android程序的4大組件之一,是Android程序的表示層。程序的每一個顯示屏幕就是一個Activity,它上面可以顯示一些控件也可以監聽並處理用戶的事件做出響應,Activity之間通過Intent進行通信。

一、Activity 的生命周期:

為了理解生命周期,先說一下任務:任務其實就是“應用程序”,它是由一個或多個Activity組成的共同完成一個完整的用戶體驗。

比如我們打開QQ首先進入聯系人列表界面,這個界面就是一個Activity:

點擊“添加好友”便進入到搜索的Activity:

點擊一條搜索結果便進入到了名片的Activity:

一個任務的Activity是由棧的形式存儲的,棧底的是啟動整個任務的Activity,棧頂的是當前運行的用戶可以交互的Activity,當一個activity 啟動另外一個的時候,新的activity 就被壓入棧,並成為當前運行的activity。而前一個activity 仍保持在棧之中。當用戶按下BACK 鍵的時候,當前activity 出棧,而前一個恢復為當前運行的activity。棧中的Activity 永遠不會重排,只會壓入或彈出。

任務中的所有Activity 是作為一個整體進行移動的。整個的任務(即Activity 棧)可以移到前台,或退至后台。舉個例子說,比如當前任務在棧中存有四個Activity──三個在當前Activity 之下。當用戶按下HOME 鍵的時候,回到了系統界面,然后選擇了一個新的應用程序(也就是一個新任務)。則當前任務轉入后台,而新任務的根Activity 顯示出來。然后,用戶再次回到了系統界面選擇了前一個應用程序(上一個任務)。於是那個任務,帶着它棧中所有的四個Activity,再一次的到了前台。當用戶按下BACK 鍵的時候,屏幕不會回到用戶剛才離開的任務。取而代之,當前任務的棧中最上面的Activity 被彈出,倒數第二個Activity 顯示了出來。

Android系統是一個多任務(Multi-Task)的操作系統,可以在用手機聽音樂的同時執行其他多個程序。每多執行一個應用程序,就會多耗費一些系統內存,當同時執行的程序過多,或是關閉的程序沒有正確釋放掉內存,系統就會覺得越來越慢,甚至不穩定。為了解決這個問題, Android 引入了一個新的機制-- 生命周期(Life Cycle)。Android 應用程序的生命周期是由Android 框架進行管理,而不是由應用程序控制。通常,每一個應用程序(入口一般會是一個Activity 的onCreate 方法),都會產生一個進程(Process)。當系統內存即將不足的時候,會依照優先級自動進行進程(process)的回收。不管是使用者或開發者, 都無法確定的應用程序何時會被回收。所以為了防止數據丟失和其他問題,了解生命周期很重要。

 

1、四種狀態:

1.活動(Active/Running)狀態:
當Activity運行在屏幕前台(處於當前任務活動棧的最上面),此時它獲取了焦點能響應用戶的操作,屬於運行狀態,同一個時刻只會有一個Activity 處於活動(Active)或運行(Running)狀態。
2.暫停(Paused)狀態:
當Activity失去焦點但仍對用戶可見(如在它之上有另一個透明的Activity或Toast、AlertDialog等彈出窗口時)它處於暫停狀態。暫停的Activity仍然是存活狀態(它保留着所有的狀態和成員信息並保持和窗口管理器的連接),但是當系統內存極小時可以被系統殺掉。
3.停止(Stopped)狀態:
完全被另一個Activity遮擋時處於停止狀態,它仍然保留着所有的狀態和成員信息。只是對用戶不可見,當其他地方需要內存時它往往被系統殺掉。
4.非活動(Dead)狀態:
Activity 尚未被啟動、已經被手動終止,或已經被系統回收時處於非活動的狀態,要手動終止Activity,可以在程序中調用"finish"方法。如果是(按根據內存不足時的回收規則)被系統回收,可能是因為內存不足了。

內存不足時,Dalvak 虛擬機會根據其內存回收規則來回收內存:

1.先回收與其他Activity 或Service/Intent Receiver 無關的進程(即優先回收獨立的Activity)因此建議我們的一些(耗時)后台操作,最好是作成Service的形式。
2.不可見(處於Stopped狀態的)Activity。
3.Service進程(除非真的沒有內存可用時會被銷毀)。
4.非活動的可見的(Paused狀態的)Activity。
5.當前正在運行(Active/Running狀態的)Activity。

2、七個重要方法,當Activity從一種狀態進入另一狀態時系統會自動調用下面相應的方法來通知用戶這種變化:

1.onCreate(Bundle savedInstanceState):
當Activity第一次被實例化的時候系統會調用,整個生命周期只調用1次這個方法通常用於初始化設置,為Activity設置所要使用的布局文件,為按鈕綁定監聽器等靜態的設置操作。
2.onStart():
當Activity可見未獲得用戶焦點不能交互時系統會調用。
3.onRestart():
當Activity已經停止然后重新被啟動時系統會調用。
4.onResume():
當Activity可見且獲得用戶焦點能交互時系統會調用。
5.onPause():
當系統啟動另外一個新的Activity時,在新Activity啟動之前被系統調用保存現有的Activity中的持久數據、停止動畫等,這個實現方法必須非常快。當由系統而不是用戶自己出於回收內存時,關閉了Activity 之后。用戶會期望當他再次回到這個Activity 的時候,它仍保持着上次離開時的樣子。此時用到了onSaveInstanceState(),方法onSaveInstanceState()用來保存Activity被殺之前的狀態,在onPause()之前被觸發,當系統為了節省內存銷毀了Activity(用戶本不想銷毀)時就需要重寫這個方法了,當此Activity再次被實例化時會通過onCreate(Bundle savedInstanceState)將已經保存的臨時狀態數據傳入。因為onSaveInstanceState()方法不總是被調用,因為有些場景是不需要保存狀態數據的。 比如用戶按下BACK鍵退出activity時, 用戶顯然想要關閉這個activity,此時是沒有必要保存數據以供下次恢復的,也就是onSaveInstanceState()方法不會被調用。onSaveInstanceState()方法觸發條件為(按下HOME鍵,按下電源按鍵關閉屏幕,橫豎屏切換情況下),應該僅重寫onSaveInstanceState()來記錄Activity的臨時狀態,而不是持久的數據。應該使用onPause()來存儲持久數據。
6.onStop():
當Activity被新的Activity完全覆蓋不可見時被系統調用。
7.onDestroy():
當Activity(用戶調用finish()或系統由於內存不足)被系統銷毀殺掉時系統調用,(整個生命周期只調用1次)用來釋放onCreate ()方法中創建的資源,如結束線程等。

3、三個嵌套循環

1.Activity完整的生命周期:從第一次調用onCreate()開始直到調用onDestroy()結束
2.Activity的可視生命周期:從調用onStart()到相應的調用onStop()在這兩個方法之間,可以保持顯示Activity所需要的資源。如在onStart()中注冊一個廣播接收者監聽影響你的UI的改變,在onStop() 中注銷。
3.Activity的前台生命周期:從調用onResume()到相應的調用onPause()。

舉例說明:
有3個Acitivity,分別用One,Two(透明的),Three表示,One是應用啟動時的主Activity;

啟動第一個界面Activity One時,它的次序是:
onCreate (ONE) - onStart (ONE) - onResume(ONE)
點"打開透明Activity"按鈕時,這時走的次序是:
onPause(ONE) - onCreate(TWO) - onStart(TWO) - onResume(TWO)
再點back回到第一個界面,Two會被殺這時走的次序是:
onPause(TWO) - onActivityResult(ONE) - onResume(ONE) - onStop(TWO) - onDestroy(TWO)
點"打開全屏Activity"按鈕時,這時走的次序是:
onPause(ONE) - onCreate(Three) - onStart(Three) - onResume(Three) - onStop(ONE)
再點back回到第一個界面,Three會被殺這時走的次序是:
onPause(Three) - onActivityResult(ONE) - onRestart(ONE) - onStart(ONE)- onResume(ONE) - onStop(Three) - onDestroy(Three)
再點back退出應用時,它的次序是:
onPause(ONE) - onStop(ONE) - onDestroy(ONE)

二、代碼示例:

新建一個測試項目,並在MainActivity寫以下代碼:

 1 /** Called when the activity is first created. */
 2     @Override
 3     public void onCreate(Bundle savedInstanceState) {
 4         super.onCreate(savedInstanceState);
 5         setContentView(R.layout.main);
 6         Toast.makeText(this, "onCreate(Bundle savedInstanceState)方法被調用了。", Toast.LENGTH_SHORT).show();
 7     }
 8     
 9     @Override
10     public void onStart(){
11         super.onStart();
12         Toast.makeText(this, "onStart()方法被調用了。", Toast.LENGTH_SHORT).show();
13     }
14     
15     @Override
16     public void onRestoreInstanceState(Bundle savedInstanceState){
17         super.onRestoreInstanceState(savedInstanceState);
18         Toast.makeText(this, "onRestoreInstanceState(Bundle savedInstanceState)方法被調用了。", Toast.LENGTH_SHORT).show();
19     }
20     
21     @Override
22     public void onRestart(){
23         super.onRestart();
24         Toast.makeText(this, "onRestart()方法被調用了。", Toast.LENGTH_SHORT).show();    
25     }
26     
27     @Override
28     public void onSaveInstanceState(Bundle savedInstanceState){
29         super.onSaveInstanceState(savedInstanceState);
30         Toast.makeText(this, "onSaveInstanceState(Bundle savedInstanceState)方法被調用了。", Toast.LENGTH_SHORT).show();
31     }
32     
33     @Override
34     public void onPause(){
35         super.onPause();
36         Toast.makeText(this, "onPause()方法被調用了。", Toast.LENGTH_SHORT).show();
37     }
38     
39     @Override
40     public void onResume(){
41         super.onResume();
42         Toast.makeText(this, "onResume方法被調用了。", Toast.LENGTH_SHORT).show();
43     }
44     
45     @Override
46     public void onStop(){
47         super.onStop();
48         Toast.makeText(this, "onStop()方法被調用了。", Toast.LENGTH_SHORT).show();
49     }
50     
51     @Override
52     public void onDestroy(){
53         super.onDestroy();
54         Toast.makeText(this, "onDestroy()方法被調用了。", Toast.LENGTH_SHORT).show();
55     }
56     
57     @Override
58     public void onConfigurationChanged(Configuration newConfig){
59         super.onConfigurationChanged(newConfig);
60         Toast.makeText(this, "onConfigurationChanged()方法被調用了。", Toast.LENGTH_SHORT).show();
61     }

運行后在模擬器上觀察方法的調用情況。

三、橫豎屏切換時候Activity的生命周期:

1.默認設置切換時的生命周期:

運行剛才新建的測試項目,Toast消息的提示調用順序是:

“onCreate”->"onStart"->"onResume"

按crtl+f12切換模擬器為橫屏時,Toast消息的提示調用順序是:

“onSaveInstanceState”->"onPause"->"onStop"->"onDestroy"->"onCreate"->"onStart"->"onRestoreInstanceState"->"onResume"

再次按按crtl+f12切換模擬器為豎屏時,發現Toast消息顯示了2次相同的調用順序:

“onSaveInstanceState”->"onPause"->"onStop"->"onDestroy"->"onCreate"->"onStart"->"onRestoreInstanceState"->"onResume"->
"onSaveInstanceState"->"onPause"->"onStop"->"onDestroy"->"onCreate"->"onStart"->"onRestoreInstanceState"->"onResume"

2.修改AndroidManifest.xml,在該Activity添加android:configChanges="orientation":

1 <activity android:name=".MainActivityLife"
2                   android:label="@string/app_name" android:configChanges="orientation">
3             <intent-filter>
4                 <action android:name="android.intent.action.MAIN" />
5                 <category android:name="android.intent.category.LAUNCHER" />
6             </intent-filter>
7 </activity>

重新生成並運行項目,然后按crtl+f12切換模擬器為橫屏時,Toast消息的提示調用順序是:

“onSaveInstanceState”->"onPause"->"onStop"->"onDestroy"->"onCreate"->"onStart"->"onRestoreInstanceState"->"onResume"

再次按按crtl+f12切換模擬器為豎屏時,Toast消息的提示多了一個"onConfigurationChanged":

“onSaveInstanceState”->"onPause"->"onStop"->"onDestroy"->"onCreate"->"onStart"->"onRestoreInstanceState"->"onResume"->"onConfigurationChanged"

3.修改AndroidManifest.xml,把剛才添加的android:configChanges="orientation"改為android:configChanges="keyboardHidden|orientation"

1 <activity android:name=".MainActivityLife"
2                   android:label="@string/app_name" android:configChanges="keyboardHidden|orientation">
3             <intent-filter>
4                 <action android:name="android.intent.action.MAIN" />
5                 <category android:name="android.intent.category.LAUNCHER" />
6             </intent-filter>
7 </activity>

重新生成並運行項目,然后按crtl+f12切換模擬器為橫屏時,Toast消息只提示了"onConfigurationChanged":

"onConfigurationChanged"

再次按按crtl+f12切換模擬器為豎屏時,Toast消息提示了2次"onConfigurationChanged":

"onConfigurationChanged"->"onConfigurationChanged"

4.總結:

不設置Activity的android:configChanges時,切屏會重新調用各個生命周期,切橫屏時會執行一次,切豎屏時會執行兩次。

設置Activity的android:configChanges="orientation"時,切屏還是會重新調用各個生命周期,切橫、豎屏時只會執行一次,且在豎屏時執行了一次"onConfigurationChanged"。

設置Activity的android:configChanges="keyboardHidden|orientation"時,切屏不會重新調用各個生命周期,只會執行"onConfigurationChanged"。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM