Android四大基本組件介紹與生命週期 Android四大基本組件介紹與生命週期

Android四大基本組件分別是Activity,Service服務,Content Provider內容提供者,BroadcastReceiver廣播接收器。html

一:瞭解四大基本組件linux

Activity :android

應用程序中,一個Activity一般就是一個單獨的屏幕,它上面能夠顯示一些控件也能夠監聽並處理用戶的事件作出響應。數據庫

Activity之間經過Intent進行通訊。在Intent 的描述結構中,有兩個最重要的部分:動做和動做對應的數據。瀏覽器

典型的動做類型有:M AIN(activity的門戶)、VIEW、PICK、EDIT 等。而動做對應的數據則以URI 的形式進行表示。例如:要查看一我的的聯繫方式,你須要建立一個動做類型爲VIEW 的intent,以及一個表示這我的的URI。網絡

與之有關係的一個類叫IntentFilter。相對於intent 是一個有效的作某事的請求,一個intentfilter 則用於描述一個activity(或者IntentReceiver)可以操做哪些intent。一個activity 若是要顯示一我的的聯繫方式時,須要聲明一個IntentFilter,這個IntentFilter 要知道怎麼去處理VIEW 動做和表示一我的的URI。IntentFilter 須要在AndroidManifest.xml 中定義。經過解析各類intent,從一個屏幕導航到另外一個屏幕是很簡單的。當向前導航時,activity 將會調用startActivity(Intent myIntent)方法。而後,系統會在全部安裝的應用程序中定義的IntentFilter 中查找,找到最匹配myIntent 的Intent 對應的activity。新的activity 接收到myIntent 的通知後,開始運行。當startActivity 方法被調用將觸發解析myIntent 的動做,這個機制提供了兩個關鍵好處:app

A、Activities 可以重複利用從其它組件中以Intent 的形式產生的一個請求;框架

B、Activities 能夠在任什麼時候候被一個具備相同IntentFilter 的新的Activity 取代。異步

AndroidManifest文件中含有以下過濾器的Activity組件爲默認啓動類當程序啓動時系統自動調用它ide

<intent-filter>
       <action android:name="android.intent.action.MAIN" />
       <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

BroadcastReceive廣播接收器:

你的應用可使用它對外部事件進行過濾只對感興趣的外部事件(如當電話呼入時,或者數據網絡可用時)進行接收並作出響應。廣播接收器沒有用戶界面。然而,它們能夠啓動一個activity或serice 來響應它們收到的信息,或者用NotificationManager 來通知用戶。通知能夠用不少種方式來吸引用戶的注意力──閃動背燈、震動、播放聲音等。通常來講是在狀態欄上放一個持久的圖標,用戶能夠打開它並獲取消息。

廣播類型:

普通廣播經過Context.sendBroadcast(Intent myIntent)發送的

有序廣播經過Context.sendOrderedBroadcast(intent, receiverPermission)發送的,該方法第2個參數決定該廣播的級別,級別數值是在 -1000 到 1000 之間 , 值越大 , 發送的優先級越高;廣播接收者接收廣播時的級別級別(可經過intentfilter中的priority進行設置設爲2147483647時優先級最高),同級別接收的前後是隨機的, 再到級別低的收到廣播,高級別的或同級別先接收到廣播的能夠經過abortBroadcast()方法截斷廣播使其餘的接收者沒法收到該廣播,還有其餘構造函數

異步廣播經過Context.sendStickyBroadcast(Intent myIntent)發送的,還有sendStickyOrderedBroadcast(intent, resultReceiver, scheduler,  initialCode, initialData, initialExtras)方法,該方法具備有序廣播的特性也有異步廣播的特性;發送異步廣播要: <uses-permission android:name="android.permission.BROADCAST_STICKY" />權限,接收並處理完Intent後,廣播依然存在,直到你調用removeStickyBroadcast(intent)主動把它去掉

注意:發送廣播時的intent參數與Contex.startActivity()啓動起來的Intent不一樣,前者能夠被多個訂閱它的廣播接收器調用,後者只能被一個(Activity或service)調用

監聽廣播Intent步驟:

1>             寫一個繼承BroadCastReceiver的類,重寫onReceive()方法,廣播接收器僅在它執行這個方法時處於活躍狀態。當onReceive()返回後,它即爲失活狀態,注意:爲了保證用戶交互過程的流暢,一些費時的操做要放到線程裏,如類名SMSBroadcastReceiver

2>            註冊該廣播接收者,註冊有兩種方法程序動態註冊和AndroidManifest文件中進行靜態註冊(可理解爲系統中註冊)以下:

        靜態註冊,註冊的廣播,下面的priority表示接收廣播的級別"2147483647"爲最高優先級

<receiver android:name=".SMSBroadcastReceiver" >
  <intent-filter android:priority = "2147483647" >
    <action android:name="android.provider.Telephony.SMS_RECEIVED" />
  </intent-filter>
</receiver >

動態註冊,通常在Activity可交互時onResume()內註冊BroadcastReceiver

IntentFilter intentFilter=new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(mBatteryInfoReceiver ,intentFilter);

//反註冊
unregisterReceiver(receiver);

注意:

1.生命週期只有十秒左右,若是在 onReceive() 內作超過十秒內的事情,就會報ANR(Application No Response) 程序無響應的錯誤信息,若是須要完成一項比較耗時的工做 , 應該經過發送 Intent 給 Service, 由Service 來完成 . 這裏不能使用子線程來解決 , 由於 BroadcastReceiver 的生命週期很短 , 子線程可能尚未結束BroadcastReceiver 就先結束了 .BroadcastReceiver 一旦結束 , 此時 BroadcastReceiver 的所在進程很容易在系統須要內存時被優先殺死 , 由於它屬於空進程 ( 沒有任何活動組件的進程 ). 若是它的宿主進程被殺死 , 那麼正在工做的子線程也會被殺死 . 因此採用子線程來解決是不可靠的

2. 動態註冊廣播接收器還有一個特色,就是當用來註冊的Activity關掉後,廣播也就失效了。靜態註冊無需擔心廣播接收器是否被關閉,只要設備是開啓狀態,廣播接收器也是打開着的。也就是說哪怕app自己未啓動,該app訂閱的廣播在觸發時也會對它起做用

系統常見廣播Intent,如開機啓動、電池電量變化、時間改變等廣播

Service 服務:

一個Service 是一段長生命週期的,沒有用戶界面的程序,能夠用來開發如監控類程序。

比較好的一個例子就是一個正在從播放列表中播放歌曲的媒體播放器。在一個媒體播放器的應用中,應該會有多個activity,讓使用者能夠選擇歌曲並播放歌曲。然而,音樂重放這個功能並無對應的activity,由於使用者固然會認爲在導航到其它屏幕時音樂應該還在播放的。在這個例子中,媒體播放器這個activity 會使用Context.startService()來啓動一個service,從而能夠在後臺保持音樂的播放。同時,系統也將保持這個service 一直執行,直到這個service 運行結束。另外,咱們還能夠經過使用Context.bindService()方法,鏈接到一個service 上(若是這個service 尚未運行將啓動它)。當鏈接到一個service 以後,咱們還能夠service 提供的接口與它進行通信。拿媒體播放器這個例子來講,咱們還能夠進行暫停、重播等操做。

Service使用步驟以下

       1>繼承service類

       2>AndroidManifast.xml配置清單文件中<application>節點裏對服務進行配置

              <service name=".SMSService"/>

服務不能本身運行,須要經過Contex.startService()或Contex.bindService()啓動服務

經過startService()方法啓動的服務於調用者沒有關係,即便調用者關閉了,服務仍然運行想中止服務要調用Context.stopService(),此時系統會調用onDestory(),使用此方法啓動時,服務首次啓動系統先調用服務的onCreate()-->onStart(),若是服務已經啓動再次調用只會觸發onStart()方法

使用bindService()啓動的服務與調用者綁定,只要調用者關閉服務就終止,使用此方法啓動時,服務首次啓動系統先調用服務的onCreate()-->onBind(),若是服務已經啓動再次調用不會再觸發這2個方法,調用者退出時系統會調用服務的onUnbind()-->onDestory(),想主動解除綁定可以使用Contex.unbindService(),系統依次調用onUnbind()-->onDestory();

Content Provider內容提供者 :

android平臺提供了Content Provider使一個應用程序的指定數據集提供給其餘應用程序。這些數據能夠存儲在文件系統中、在一個SQLite數據庫、或以任何其餘合理的方式,

其餘應用能夠經過ContentResolver類(見ContentProviderAccessApp例子)從該內容提供者中獲取或存入數據.(至關於在應用外包了一層殼),

只有須要在多個應用程序間共享數據是才須要內容提供者。例如,通信錄數據被多個應用程序使用,且必須存儲在一個內容提供者中

它的好處:統一數據訪問方式。

android系統自帶的內容提供者(頂級的表示數據庫名,非頂級的都是表名)這些內容提供者在SDK文檔的android.provider Java包中都有介紹。見:http://developer.android.com/reference/android/provider/package-summary.html

├────Browser

├────CallLog

├────Contacts

│                ├────Groups

│                ├────People

│                ├────Phones

│                └────Photos

├────Images

│                └────Thumbnails

├────MediaStore

│                ├────Albums

│                ├────Artists

│                ├────Audio

│                ├────Genres

│                └────Playlists

├────Settings

└────Video

 CallLog:地址和接收到的電話信息

 Contact.People.Phones:存儲電話號碼

 Setting.System:系統設置和偏好設置

使用Content Provider對外共享數據的步驟

1>繼承ContentProvider類並根據需求重寫如下方法:

 

      

複製代碼
    public boolean onCreate();//處理初始化操做

       /**
        * 插入數據到內容提供者(容許其餘應用向你的應用中插入數據時重寫)
        * @param uri
        * @param initialValues 插入的數據
        * @return
        */
       public Uri insert(Uri uri, ContentValues initialValues);

       /**
        * 從內容提供者中刪除數據(容許其餘應用刪除你應用的數據時重寫)
        * @param uri
        * @param selection 條件語句
        * @param selectionArgs 參數
        * @return
        */
       public int delete(Uri uri, String selection, String[] selectionArgs);

       /**
        * 更新內容提供者已存在的數據(容許其餘應用更新你應用的數據時重寫)
        * @param uri
        * @param values 更新的數據
        * @param selection 條件語句
        * @param selectionArgs 參數
        * @return
        */
       public int update(Uri uri, ContentValues values, String selection,
                     String[] selectionArgs);

       /**
        * 返回數據給調用者(容許其餘應用從你的應用中獲取數據時重寫)
        * @param uri
        * @param projection 列名
        * @param selection 條件語句
        * @param selectionArgs 參數
        * @param sortOrder 排序
        * @return
        */
       public Cursor query(Uri uri, String[] projection, String selection,
                     String[] selectionArgs, String sortOrder) ;         

       /**
        * 用於返回當前Uri所表明數據的MIME類型
        * 若是操做的數據爲集合類型(多條數據),那麼返回的類型字符串應該爲vnd.android.cursor.dir/開頭
        * 例如要獲得全部person記錄的Uri爲content://com.bravestarr.provider.personprovider/person,
     *   那麼返回的MIME類型字符串應該爲"vnd.android.cursor.dir/person" * 若是操做的數據爲單一數據,那麼返回的類型字符串應該爲vnd.android.cursor.item/開頭 * 例如要獲得id爲10的person記錄的Uri爲content://com.bravestarr.provider.personprovider/person/10,
     *   那麼返回的MIME類型字符串應該爲"vnd.android.cursor.item/person" *
@param uri */ public String getType(Uri uri)
複製代碼

這些方法中的Uri參數,獲得後須要進行解析而後作對應處理,Uri表示要操做的數據,包含兩部分信息:

       1.須要操做的contentprovider

       2.對contentprovider中的什麼數據進行操做,一個Uri格式:結構頭://authorities(域名)/路徑(要操做的數據,根據業務而定)

              content://com.bravestarr.provider.personprovider/person/10

說明:contentprovider的結構頭已經由android規定爲content://

authorities用於惟一標識這個contentprovider程序,外部調用者能夠根據這個找到他

路徑表示咱們要操做的數據,路徑的構建根據業務而定.路徑格式以下:                                                        

       要操做person錶行號爲10的記錄,能夠這樣構建/person/10

       要操做person表的全部記錄,能夠這樣構建/person

2>在AndroidManifest.xml中使用<provider>對ContentProvider進行配置註冊(內容提供者註冊它本身就像網站註冊域名),ContentProvider採用authoritie(原意受權,可理解爲域名)做爲惟一標識,方便其餘應用能找到

複製代碼
<application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <!-- authorities屬性命名建議:公司名.provider.SomeProvider-->
        <provider android:name=".PersonProvider" android:authorities="com.bravestarr.provider.personprovider"/>
         ...
</application>
複製代碼

關於四大基本組件的一個總結:

1>    4大組件的註冊

4大基本組件都須要註冊才能使用,每一個Activity、service、Content Provider內容提供者都須要在AndroidManifest文件中進行配置AndroidManifest文件中未進行聲明的activity、服務以及內容提供者將不爲系統所見,從而也就不可用,而BroadcastReceive廣播接收者的註冊分靜態註冊(在AndroidManifest文件中進行配置)和經過代碼動態建立並以調用Context.registerReceiver()的方式註冊至系統。須要注意的是在AndroidManifest文件中進行配置的廣播接收者會隨系統的啓動而一直處於活躍狀態,只要接收到感興趣的廣播就會觸發(即便程序未運行)

AndroidManifest文件中進行註冊格式以下:

<activity>元素的name 屬性指定了實現了這個activity 的Activity 的子類。icon 和label 屬性指向了包含展現給用戶的此activity 的圖標和標籤的資源文件。

<service> 元素用於聲明服務

<receiver> 元素用於聲明廣播接收器

<provider> 元素用於聲明內容提供者

2>   4大組件的激活

• 容提供者的激活:當接收到ContentResolver 發出的請求後,內容提供者被激活。而其它三種組件──activity、服務和廣播接收器被一種叫作intent 的異步消息所激活

• Activity的激活經過傳遞一個Intent 對象至Context.startActivity()或Activity.startActivityForResult()以載入(或指定新工做給)一個activity。相應的activity 能夠經過調用getIntent() 方法來查看激活它的intent。若是它指望它所啓動的那個activity 返回一個結果,它會以調用startActivityForResult()來取代startActivity()。好比說,若是它啓動了另一個Activity 以使用戶挑選一張照片,它也許想知道哪張照片被選中了。結果將會被封裝在一個Intent 對象中,並傳遞給發出調用的activity 的onActivityResult() 方法。

• 服務的激活能夠經過傳遞一個Intent 對象至Context.startService()或Context.bindService()前者Android 調用服務的onStart()方法並將Intent 對象傳遞給它,後者Android 調用服務的onBind()方法將這個Intent 對象傳遞給它

• 發送廣播能夠經過傳遞一個Intent 對象至給Context.sendBroadcast() 、

Context.sendOrderedBroadcast()或Context.sendStickyBroadcast()Android 會調用全部對此廣播有興趣的廣播接收器的onReceive()方法,將intent 傳遞給它們

3>   四大組件的關閉

內容提供者僅在響應ContentResolver 提出請求的時候激活。而一個廣播接收器僅在響應廣播信息的時候激活。因此,沒有必要去顯式的關閉這些組件。

Activity關閉:能夠經過調用它的finish()方法來關閉一個activity

服務關閉:對於經過startService()方法啓動的服務要調用Context.stopService()方法關閉服務,使用bindService()方法啓動的服務要調用Contex.unbindService ()方法關閉服務

二:四大組件的生命週期

     介紹生命週期以前,先提一下任務的概念

任務其實就是activity 的棧它由一個或多個Activity組成的共同完成一個完整的用戶體驗, 換句話說任務就是」 應用程序」 (能夠是一個也能夠是多個,好比假設你想讓用戶看到某個地方的街道地圖。而已經存在一個具備此功能的activity 了,那麼你的activity 所須要作的工做就是把請求信息放到一個Intent 對象裏面,並把它傳遞給startActivity()。因而地圖瀏覽器就會顯示那個地圖。而當用戶按下BACK 鍵的時候,你的activity 又會再一次的顯示在屏幕上,此時任務是由2個應用程序中的相關activity組成的)棧底的是啓動整個任務的Activity,棧頂的是當前運行的用戶能夠交互的Activity,當一個activity 啓動另一個的時候,新的activity 就被壓入棧,併成爲當前運行的activity。而前一個activity 仍保持在棧之中。當用戶按下BACK 鍵的時候,當前activity 出棧,而前一個恢復爲當前運行的activity。棧中保存的實際上是對象,棧中的Activity 永遠不會重排,只會壓入或彈出,因此若是發生了諸如須要多個地圖瀏覽器的狀況,就會使得一個任務中出現多個同一Activity 子類的實例同時存在。

任務中的全部activity 是做爲一個總體進行移動的。整個的任務(即activity 棧)能夠移到前臺,或退至後臺。舉個例子說,好比當前任務在棧中存有四個activity──三個在當前activity 之下。當用戶按下HOME 鍵的時候,回到了應用程序加載器,而後選擇了一個新的應用程序(也就是一個新任務)。則當前任務遁入後臺,而新任務的根activity 顯示出來。而後,過了一小會兒,用戶再次回到了應用程序加載器而又選擇了前一個應用程序(上一個任務)。因而那個任務,帶着它棧中全部的四個activity,再一次的到了前臺。當用戶按下BACK 鍵的時候,屏幕不會顯示出用戶剛纔離開的activity(上一個任務的根

activity)。取而代之,當前任務的棧中最上面的activity 被彈出,而同一任務中的上一個activity 顯示了出來。

Activity棧:先進後出規則

                                                    

Android系統是一個多任務(Multi-Task)的操做系統,能夠在用手機聽音樂的同時,也執行其餘多個程序。每多執行一個應用程序,就會多耗費一些系統內存,當同時執行的程序過多,或是關閉的程序沒有正確釋放掉內存,系統就會以爲愈來愈慢,甚至不穩定。

爲了解決這個問題, Android 引入了一個新的機制-- 生命週期(Life Cycle)。

Android 應用程序的生命週期是由Android 框架進行管理,而不是由應用程序直接控

制。一般,每個應用程序(入口通常會是一個Activity 的onCreate 方法),都會產生

一個進程(Process)。當系統內存即將不足的時候,會依照優先級自動進行進程(process)的回收。無論是使用者或開發者, 都沒法肯定的應用程序什麼時候會被回收。因此爲了很好的防止數據丟失和其餘問題,瞭解生命週期很重要。

Activity生命週期

                                                           

圖3.1activity生命週期圖

Activity整個生命週期的4種狀態、7個重要方法和3個嵌套循環

1>   四種狀態

  1.       活動(Active/Running)狀態

當Activity運行在屏幕前臺(處於當前任務活動棧的最上面),此時它獲取了焦點能響應用戶的操做,屬於運行狀態,同一個時刻只會有一個Activity 處於活動(Active)或運行

(Running)狀態

  1.     暫停(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>  7個重要方法,當Activity從一種狀態進入另外一狀態時系統會自動調用下面相應的方

法來通知用戶這種變化

當Activity第一次被實例化的時候系統會調用,

整個生命週期只調用1次這個方法

一般用於初始化設置: 一、爲Activity設置所要使用的佈局文件二、爲按鈕綁定監聽器等靜態的設置操做

      onCreate(Bundle savedInstanceState);

      

當Activity可見未得到用戶焦點不能交互時系統會調用

      onStart();

 

當Activity已經中止而後從新被啓動時系統會調用

      onRestart();

      

當Activity可見且得到用戶焦點能交互時系統會調用

      onResume();

      

當系統啓動另一個新的Activity時,在新Activity啓動以前被系統調用保存現有的Activity中的持久數據、中止動畫等,這個實現方法必須很是快。當系統而不是用戶本身出於回收內存時,關閉了activity 以後。用戶會指望當他再次回到這個activity 的時候,它仍保持着上次離開時的樣子。此時用到了onSaveInstanceState(),方法onSaveInstanceState()用來保存Activity被殺以前的狀態,在onPause()以前被觸發,當系統爲了節省內存銷燬了Activity(用戶本不想銷燬)時就須要重寫這個方法了,當此Activity再次被實例化時會經過onCreate(Bundle savedInstanceState)將已經保存的臨時狀態數據傳入由於onSaveInstanceState()方法不老是被調用,觸發條件爲(按下HOME鍵,按下電源按鍵關閉屏幕,橫豎屏切換狀況下),你應該僅重寫onSaveInstanceState()來記錄activity的臨時狀態,而不是持久的數據。應該使用onPause()來存儲持久數據。

      onPause();

 

當Activity被新的Activity徹底覆蓋不可見時被系統調用

      onStop();

      

當Activity(用戶調用finish()或系統因爲內存不足)被系統銷燬殺掉時系統調用,(整個生命週期只調用1次)用來釋放onCreate ()方法中建立的資源,如結束線程等

      onDestroy();

      

3>  3個嵌套循環

             1.Activity完整的生命週期:從第一次調用onCreate()開始直到調用onDestroy()結束

             2.Activity的可視生命週期:從調用onStart()到相應的調用onStop()

                    在這兩個方法之間,能夠保持顯示Activity所須要的資源。如在onStart()中註冊一個廣播接收者監聽影響你的UI的改變,在onStop() 中註銷。

             3.Activity的前臺生命週期:從調用onResume()到相應的調用onPause()。

             

      舉例說明:

例1:有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)           

 

例2:橫豎屏切換時候Activity的生命週期

他切換時具體的生命週期是怎麼樣的:

一、新建一個Activity,並把各個生命週期打印出來

二、運行Activity,獲得以下信息

onCreate-->
onStart-->
onResume-->

三、按crtl+f12切換成橫屏時

onSaveInstanceState-->
onPause-->
onStop-->
onDestroy-->
onCreate-->
onStart-->
onRestoreInstanceState-->
onResume-->

四、再按crtl+f12切換成豎屏時,發現打印了兩次相同的log

onSaveInstanceState-->
onPause-->
onStop-->
onDestroy-->
onCreate-->
onStart-->
onRestoreInstanceState-->
onResume-->
onSaveInstanceState-->
onPause-->
onStop-->
onDestroy-->
onCreate-->
onStart-->
onRestoreInstanceState-->
onResume-->

五、修改AndroidManifest.xml,把該Activity添加android:configChanges="orientation",執行步驟3

onSaveInstanceState-->
onPause-->
onStop-->
onDestroy-->
onCreate-->
onStart-->
onRestoreInstanceState-->
onResume-->

六、再執行步驟4,發現不會再打印相同信息,但多打印了一行onConfigChanged

onSaveInstanceState-->
onPause-->
onStop-->
onDestroy-->
onCreate-->
onStart-->
onRestoreInstanceState-->
onResume-->
onConfigurationChanged-->

七、把步驟5的android:configChanges="orientation" 改爲 android:configChanges="orientation|keyboardHidden",執行步驟3,就只打印onConfigChanged

onConfigurationChanged-->

八、執行步驟4

onConfigurationChanged-->
onConfigurationChanged-->

 總結:

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

二、設置Activity的android:configChanges="orientation"時,切屏仍是會從新調用各個生命週期,切橫、豎屏時只會執行一次

三、設置Activity的android:configChanges="orientation|keyboardHidden"時,切屏不會從新調用各個生命週期,只會執行onConfigurationChanged方法

 
總結一下整個Activity的生命週期

補充一點,當前Activity產生事件彈出Toast和AlertDialog的時候Activity的生命週期不會有改變

Activity運行時按下HOME鍵(跟被徹底覆蓋是同樣的):onSaveInstanceState --> onPause --> onStop,再次進入激活狀態時: onRestart -->onStart--->onResume

BroadcastReceive廣播接收器生命週期

生命週期只有十秒左右,若是在 onReceive() 內作超過十秒內的事情,就會報ANR(Application No Response) 程序無響應的錯誤信息

它的生命週期爲從回調onReceive()方法開始到該方法返回結果後結束

Service服務生命週期

                                                             

圖3.2service生命週期圖

Service完整的生命週期:從調用onCreate()開始直到調用onDestroy()結束

Service有兩種使用方法:

1>以調用Context.startService()啓動,而以調用Context.stopService()結束

2>以調用Context.bindService()方法創建,以調用Context.unbindService()關閉

service重要的生命週期方法

當用戶調用startService ()或bindService()時,Service第一次被實例化的時候系統會調用,整個生命週期只調用1次這個方法,一般用於初始化設置。注意:屢次調用startService()或bindService()方法不會屢次觸發onCreate()方法

void onCreate()

當用戶調用stopService()或unbindService()來中止服務時被系統調用,(整個生命週期只調用1次)用來釋放onCreate()方法中建立的資源

void onDestroy()

經過startService()方法啓動的服務

      初始化結束後系統會調用該方法,用於處理傳遞給startService()的Intent對象。如音樂服務會打開Intent 來探明將要播放哪首音樂,並開始播放。注意:屢次調用startService()方法會屢次觸發onStart()方法

void onStart(Intent intent)

經過bindService ()方法啓動的服務

      初始化結束後系統會調用該方法,用來綁定傳遞給bindService 的Intent 的對象。注意:屢次調用bindService()時,若是該服務已啓動則不會再觸發此方法

IBinder onBind(Intent intent)

用戶調用unbindService()時系統調用此方法,Intent 對象一樣傳遞給該方法

boolean onUnbind(Intent intent)

若是有新的客戶端鏈接至該服務,只有當舊的調用onUnbind()後,新的纔會調用該方法

void onRebind(Intent intent)

補充:onCreate(Bundle savedInstanceState)與onSaveInstanceState(Bundle savedInstanceState)配合使用,見以下代碼,達到顯示activity被系統殺死前的狀態

複製代碼
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (null != savedInstanceState) {
            String _userid = savedInstanceState.getString("StrUserId");
            String _uid = savedInstanceState.getString("StrUid");
            String _serverid = savedInstanceState.getString("StrServerId");
            String _servername = savedInstanceState.getString("StrServerName");
            int _rate = savedInstanceState.getInt("StrRate");
            //updateUserId(_userid);
            //updateUId(_uid);
            //updateServerId(_serverid);
            //updateUserServer(_servername);
            //updateRate(_rate);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putString("StrUserId", getUserId());
        savedInstanceState.putString("StrUid", getUId());
        savedInstanceState.putString("StrServerId", getServerId());
        savedInstanceState.putString("StrServerName", getServerName());
        savedInstanceState.putInt("StrRate", getRate());
    }
複製代碼

 

引起activity摧毀和重建的其餘情形

除了系統處於內存不足的緣由會摧毀activity以外, 某些系統設置的改變也會致使activity的摧毀和重建. 例如改變屏幕方向(見上例), 改變設備語言設定, 鍵盤彈出等.

linux_riyo123

相關文章
相關標籤/搜索