編輯:關於Android編程
關於四大基本組件的一個總結:
1> 4大組件的注冊
4大基本組件都需要注冊才能使用,每個Activity、service、Content Provider內容提供者都需要在AndroidManifest文件中進行配置AndroidManifest文件中未進行聲明的activity、服務以及內容提供者將不為系統所見,從而也就不可用,而BroadcastReceive廣播接收者的注冊分靜態注冊(在AndroidManifest文件中進行配置)和通過代碼動態創建並以調用Context.registerReceiver()的方式注冊至系統。需要注意的是在AndroidManifest文件中進行配置的廣播接收者會隨系統的啟動而一直處於活躍狀態,只要接收到感興趣的廣播就會觸發(即使程序未運行)
AndroidManifest文件中進行注冊格式如下:
元素的name 屬性指定了實現了這個activity 的Activity 的子類。icon 和label 屬性指向了包含展示給用戶的此activity 的圖標和標簽的資源文件。
元素用於聲明服務
元素用於聲明廣播接收器
元素用於聲明內容提供者
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棧:先進後出規則
vcL9o6zJ9dbBsrvOyLaooaM8L3A+DQo8cD7OqsHLveK+9tXiuPbOyszio6wgQW5kcm9pZCDS/cjrwcvSu7j20MK1xLv61sYmbmRhc2g7IMn6w/zW3MbaKExpZmUgQ3ljbGUpoaM8L3A+DQo8cD5BbmRyb2lkINOm08OzzNDytcTJ+sP81tzG2srH08lBbmRyb2lkIL/yvNy9+NDQudzA7aOstviyu8rH08nTptPDs8zQ8taxvdO/2DwvcD4NCjxwPtbGoaPNqLOjo6zDv9K7uPbTptPDs8zQ8qOoyOu/2tK7sOO74crH0ru49kFjdGl2aXR5ILXEb25DcmVhdGUgt723qKOpo6y2vLvhsvrJ+jwvcD4NCjxwPtK7uPa9+LPMKFByb2Nlc3MpoaO1sc+1zbPE2rTmvLS9q7K71+O1xMqxuvKjrLvh0sDV1dPFz8i8ttfUtq+9+NDQvfizzChwcm9jZXNzKbXEu9jK1aGjsru53MrHyrnTw9Xfu/K/qrei1d+jrCC2vM7et6jIt7aotcTTptPDs8zQ8rrOyrG74bG7u9jK1aGjy/nS1M6qwcu63LrDtcS3wNa5yv2+3baqyqe6zcbky/vOyszio6zBy73iyfrD/Nbcxtq63NbY0qqhozwvcD4NCjxwPkFjdGl2aXR5yfrD/NbcxtqjujxiciAvPg0KPGltZyBhbHQ9"這裡寫圖片描述" src="/uploadfile/Collfiles/20150313/2015031308373279.jpg" title="\" />
圖3.1activity生命周期圖
Activity整個生命周期的4種狀態、7個重要方法和3個嵌套循環
1> 四種狀態
活動(Active/Running)狀態
當Activity運行在屏幕前台(處於當前任務活動棧的最上面),此時它獲取了焦點能響應用戶的操作,屬於運行狀態,同一個時刻只會有一個Activity 處於活動(Active)或運行
(Running)狀態
暫停(Paused)狀態
當Activity失去焦點但仍對用戶可見(如在它之上有另一個透明的Activity或Toast、AlertDialog等彈出窗口時)它處於暫停狀態。暫停的Activity仍然是存活狀態(它保留著所有的狀態和成員信息並保持和窗口管理器的連接),但是當系統內存極小時可以被系統殺掉
停止(Stopped)狀態完全被另一個Activity遮擋時處於停止狀態,它仍然保留著所有的狀態和成員信息。只是對用戶不可見,當其他地方需要內存時它往往被系統殺掉
非活動(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次這個方法
通常用於初始化設置: 1、為Activity設置所要使用的布局文件2、為按鈕綁定監聽器等靜態的設置操作
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的生命周期
他切換時具體的生命周期是怎麼樣的:
1、新建一個Activity,並把各個生命周期打印出來
2、運行Activity,得到如下信息
onCreate–>
onStart–>
onResume–>
3、按crtl+f12切換成橫屏時
onSaveInstanceState–>
onPause–>
onStop–>
onDestroy–>
onCreate–>
onStart–>
onRestoreInstanceState–>
onResume–>
4、再按crtl+f12切換成豎屏時,發現打印了兩次相同的log
onSaveInstanceState–>
onPause–>
onStop–>
onDestroy–>
onCreate–>
onStart–>
onRestoreInstanceState–>
onResume–>
onSaveInstanceState–>
onPause–>
onStop–>
onDestroy–>
onCreate–>
onStart–>
onRestoreInstanceState–>
onResume–>
5、修改AndroidManifest.xml,把該Activity添加android:configChanges=”orientation”,執行步驟3
onSaveInstanceState–>
onPause–>
onStop–>
onDestroy–>
onCreate–>
onStart–>
onRestoreInstanceState–>
onResume–>
6、再執行步驟4,發現不會再打印相同信息,但多打印了一行onConfigChanged
onSaveInstanceState–>
onPause–>
onStop–>
onDestroy–>
onCreate–>
onStart–>
onRestoreInstanceState–>
onResume–>
onConfigurationChanged–>
7、把步驟5的android:configChanges=”orientation” 改成 android:configChanges=”orientation|keyboardHidden”,執行步驟3,就只打印onConfigChanged
onConfigurationChanged–>
8、執行步驟4
onConfigurationChanged–>
onConfigurationChanged–>
總結:
1、不設置Activity的android:configChanges時,切屏會重新調用各個生命周期,切橫屏時會執行一次,切豎屏時會執行兩次
2、設置Activity的android:configChanges=”orientation”時,切屏還是會重新調用各個生命周期,切橫、豎屏時只會執行一次
3、設置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的摧毀和重建. 例如改變屏幕方向(見上例), 改變設備語言設定, 鍵盤彈出等.
專業的Android app開發人員會關注一些成熟的項目管理技術,以成功構建Android app,並讓這個app在Google Play Store嶄露頭角。考慮高端客
在網上看到了一個IOS組件PendulumView,實現了鐘擺的動畫效果。由於原生的進度條確實是不好看,所以想可以自定義View實現這樣的效果,以後也可以用於加載頁面的進
本文轉載於 huachao1001的專欄相信大家都曾經下定決心把23種設計模式牢記於心,每次看完之後過一段時間又忘記了~,又得回去看,腦子裡唯一依稀記得的是少
Android四大基本組件分別是Activity,Service服務,Content Provider內容提供者,BroadcastReceiver廣播接收器。一、Act