Android四大組件用了很多遍了听诸,但還是有很多細(xì)節(jié)容易忘記,所以就寫下來吧潮瓶!
Activity
Activity的生命周期
?
在這里插入圖片描述
Activity的簡單生命周期流程為onCreate();→onStart();【注:此時Activity處于不可見狀態(tài)】→onResume();【注:此時Activity處于運(yùn)行狀態(tài)】→onPause();【注:此時Activity處于暫停狀態(tài)】→onStop();【注:此時Activity處于停滯狀態(tài)】→onDestroy();【注:調(diào)用了此方法后Activity生命周期結(jié)束】
其中當(dāng)Activity正在重新啟動的時候陶冷,從不可見變?yōu)榭梢姷臅r候,會調(diào)用到onRestart();也就是說一個Activity包含七個生命周期流程
- Activity被其他Activity覆蓋其上毯辅,系統(tǒng)會調(diào)用onPause()方法埂伦,暫停當(dāng)前Activity的執(zhí)行,若用戶取消了覆蓋悉罕,系統(tǒng)會調(diào)用onResume()方法赤屋,重新進(jìn)入到運(yùn)行狀態(tài)。
- Activity跳轉(zhuǎn)到了新的Activity界面或者被后臺了或者鎖屏?xí)r壁袄,系統(tǒng)會調(diào)用onPause();然后調(diào)用onStop();使Activity進(jìn)入到停滯狀態(tài)类早,如果重新回到了該Activity界面(上一個Activity或者從后臺變?yōu)榱饲芭_時或者解開鎖屏?xí)r),系統(tǒng)會調(diào)用onRestart();再調(diào)用onStart();最后調(diào)用onResume()方法使該Activity進(jìn)入到運(yùn)行狀態(tài)
- 當(dāng)用戶退出Activity時會調(diào)用onPause();然后調(diào)用onStop();最后調(diào)用onDestory();結(jié)束Activity生命周期
- 當(dāng)Activity中彈出dialog對話框的時候嗜逻,Activity不會調(diào)用onPause();只有當(dāng)Activity啟動了dialog風(fēng)格的Activity時才會調(diào)用
- 當(dāng)Activity是由于異常情況下終止的涩僻,系統(tǒng)會調(diào)用onSaveInstance來保存當(dāng)前Activity狀態(tài),這個方法調(diào)用的時機(jī)是在onStop之前的栈顷,當(dāng)Activity重新創(chuàng)建后逆日,系統(tǒng)會調(diào)用onRestoreInstanceState,并且把Activity銷毀時的onSaveInstanceState方法保存的bundle對象作為參數(shù)同時傳遞給onRestoreInstanceState和onCreate方法
Activity的四種啟動模式
Activity有四種啟動模式 standard,singleTop,singleTask,singleInstance,這四種模式我們可以在清單文件的<Activity節(jié)點(diǎn)下通過android:launchMode來進(jìn)行配置
- standard模式:在這種模式下萄凤,activity默認(rèn)會進(jìn)入啟動它的activity所屬的任務(wù)棧中室抽。這也是默認(rèn)的一種模式
- singleTop模式:棧頂復(fù)用模式。如果新activity位于任務(wù)棧的棧頂?shù)臅r候靡努,activity不會被重新創(chuàng)建坪圾,同時它的onNewIntent方法會被回調(diào)。
- singleTask模式:棧內(nèi)復(fù)用模式惑朦。只要activity在一個棧中存在兽泄,那么多次啟動此activity不會被重新創(chuàng)建單例,系統(tǒng)會回調(diào)onNewIntent漾月。這種模式可以稱為單例模式病梢,只會存在一種,有則直接從棧中調(diào)用梁肿,沒有則創(chuàng)建并且壓入棧中
- singleInstance模式:單實(shí)例模式蜓陌。這種模式的activity只能單獨(dú)地位于一個任務(wù)棧中觅彰,這種與singleTask有點(diǎn)類似,其實(shí)也是有則直接調(diào)用护奈,沒有則創(chuàng)建并且放入棧中缔莲,只不過singleTask是可以和其他的Activity放在同一個棧中,singleInstance則是只會將創(chuàng)建的Activity放在一個棧中霉旗,并且這個棧中只會有這一個Activity實(shí)例
Service
Service分為兩種痴奏,一種是Service(這一種是運(yùn)行在主線程中的,如果要執(zhí)行耗時操作厌秒,可在service中創(chuàng)建一個異步來執(zhí)行)读拆,一種是IntentService(這是一種異步服務(wù),是繼承于Service的子類)鸵闪,所以推薦當(dāng)要執(zhí)行耗時操作時使用IntentService檐晕,如果不耗時,我們可以使用Service
Service
Service的兩種啟動方式
- 通過start方法開啟服務(wù)
- 創(chuàng)建一個類繼承Service
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
- 在清單文件中注冊這個服務(wù)
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
- 通過startService方法啟動服務(wù)
Intent intent = new Intent(this, MyService.class);
startService(intent);
- 當(dāng)不用服務(wù)的時候通過stopService()方法停止該服務(wù)
stopService(intent);
特點(diǎn): 通過start方法啟動的service一旦服務(wù)開啟就跟調(diào)用者(開啟者)沒有任何關(guān)系了蚌讼。開啟者退出了辟灰,開啟者掛了,服務(wù)還在后臺長期的運(yùn)行篡石,開啟者不能調(diào)用服務(wù)里面的方法芥喇。
- 通過bind的方式啟動服務(wù)
- 創(chuàng)建一個類繼承Service
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
- 在清單文件中注冊這個服務(wù)
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
- 通過startService方法啟動服務(wù)
Intent intent = new Intent(this, MyService.class);
bindService(Intent,ServiceConnection,int);
- 當(dāng)不用服務(wù)的時候通過stopService()方法停止該服務(wù)
unbindService(ServiceConnection);
特點(diǎn):使用bind方法啟動的服務(wù),則調(diào)用者掛了继控,服務(wù)也掛了,調(diào)用者可以調(diào)用服務(wù)中的方法
遠(yuǎn)程服務(wù)
調(diào)用者與Service不在同一個進(jìn)程冶忱,這是一種跨進(jìn)程通信的方式Android綁定遠(yuǎn)程服務(wù)
步驟:
- 在服務(wù)的內(nèi)部創(chuàng)建一個內(nèi)部類千埃,提供一個方法谒臼,可以間接調(diào)用服務(wù)的方法
- 把暴露的接口文件的擴(kuò)展名改為.aidl文件 去掉訪問修飾符
- 實(shí)現(xiàn)服務(wù)的onbind方法朝刊,繼承Bander和實(shí)現(xiàn)aidl定義的接口蜈缤,提供給外界可調(diào)用的方法
- 在activity 中綁定服務(wù)拾氓。bindService()
- 在服務(wù)成功綁定的時候會回調(diào) onServiceConnected方法 傳遞一個 IBinder對象
- aidl定義的接口.Stub.asInterface(binder) 調(diào)用接口里面的方法
IntentService
這個Service在上面也說過底哥,是一個異步服務(wù)
IntentService特征:
- 會創(chuàng)建獨(dú)立的worker線程來處理所有的Intent請求朗恳;
- 會創(chuàng)建獨(dú)立的worker線程來處理onHandleIntent()方法實(shí)現(xiàn)的代碼臀脏,無需處理多線程問題;
- 所有請求處理完成后,IntentService會自動停止佣盒,無需調(diào)用stopSelf()方法停止Service全景;
- 為Service的onBind()提供默認(rèn)實(shí)現(xiàn),返回null钥弯;
- 為Service的onStartCommand提供默認(rèn)實(shí)現(xiàn)睛蛛,將請求Intent添加到隊(duì)列中和悦;
BroadcastReceiver
廣播分為兩種吵血,一種是普通廣播蹋辅,或者稱為無序廣播,另一種是有序廣播
無序廣播與有序廣播
無序廣播是完全異步的挫掏,在同一時刻在邏輯上是能夠被所有的接收者接收到的侦另,傳遞的效率高,缺點(diǎn)是接收者不能處理結(jié)果傳給下個接收者尉共,并且無法終止廣播的傳播(其實(shí)有序廣播就是和這個相反的褒傅,有順序的傳播,兩個廣播的定義就是完全相反的袄友,這個比較好記)
Context.sendBroadcast()
發(fā)送的是普通廣播殿托,所有訂閱者都有機(jī)會獲得并進(jìn)行處理。
廣播的生命周期就是在處理完onReceive時剧蚣,系統(tǒng)將認(rèn)定他不是一個活動的對象了支竹,就是殺掉他,由于廣播的生命周期很短鸠按,所以不建議在onReceive中執(zhí)行一些耗時操作
創(chuàng)建一個廣播的步驟:
- 創(chuàng)建一個類繼承BroadcastReceiver礼搁,并且重寫其onReceive方法
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("fuck","intent-action : " + intent.getAction());
if(intent.getAction().equals("test")){
Toast.makeText(context,"fuck",Toast.LENGTH_LONG).show();
}
}
}
- 在清單文件中注冊(靜態(tài)注冊)
//廣播接收器
<receiver android:name=".broadcast.MyBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="test"/>//這里自定義一個廣播動作
</intent-filter>
</receiver>
或者動態(tài)注冊
registerReceiver(new MyBroadcastReceiver(),new IntentFilter("test"));
- 加上權(quán)限
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
- 發(fā)送廣播
Intent intent = new Intent("test");
sendBroadcast(intent);
靜態(tài)注冊和動態(tài)注冊區(qū)別
動態(tài)注冊廣播不是常駐型廣播惫谤,也就是說廣播跟隨activity的生命周期摇邦。注意: 在activity結(jié)束前蛉拙,移除廣播接收器如庭。
靜態(tài)注冊是常駐型出吹,也就是說當(dāng)應(yīng)用程序關(guān)閉后跌榔,如果有信息廣播來折剃,程序也會被系統(tǒng)調(diào)用自動運(yùn)行镶奉。
- 當(dāng)廣播為有序廣播時:
- 優(yōu)先級高的先接收
- 同優(yōu)先級的廣播接收器测蹲,動態(tài)優(yōu)先于靜態(tài)
- 同優(yōu)先級的同類廣播接收器莹捡,靜態(tài):先掃描的優(yōu)先于后掃描的,動態(tài):先注冊的優(yōu)先于后注冊的扣甲。
- 當(dāng)廣播為普通廣播時:
- 無視優(yōu)先級篮赢,動態(tài)廣播接收器優(yōu)先于靜態(tài)廣播接收器
- 同優(yōu)先級的同類廣播接收器齿椅,靜態(tài):先掃描的優(yōu)先于后掃描的,動態(tài):先注冊的優(yōu)先于后注冊的启泣。
Service小結(jié):
- 在Android 中如果要發(fā)送一個廣播必須使用sendBroadCast 向系統(tǒng)發(fā)送對其感興趣的廣播接收器中涣脚。
- 使用廣播必須要有一個intent 對象必設(shè)置其action動作對象
- 使用廣播必須在配置文件中顯式的指明該廣播對象
- 每次接收廣播都會重新生成一個接收廣播的對象
- 在BroadCastReceiver中盡量不要處理太多邏輯問題,建議復(fù)雜的邏輯交給Activity 或者 Service 去處理
- 如果在AndroidManifest.xml中注冊寥茫,當(dāng)應(yīng)用程序關(guān)閉的時候遣蚀,也會接收到廣播。在應(yīng)用程序中注冊就不產(chǎn)生這種情況了纱耻。
ContentProvider
contentprovider是android四大組件之一的內(nèi)容提供器芭梯,它主要的作用就是將程序的內(nèi)部的數(shù)據(jù)和外部進(jìn)行共享,為數(shù)據(jù)提供外部訪問接口弄喘,被訪問的數(shù)據(jù)主要以數(shù)據(jù)庫的形式存在玖喘,而且還可以選擇共享哪一部分的數(shù)據(jù)。這樣一來蘑志,對于程序當(dāng)中的隱私數(shù)據(jù)可以不共享累奈,從而更加安全。contentprovider是android中一種跨程序共享數(shù)據(jù)的重要組件急但。
自定義的內(nèi)容提供者沒用過费尽,因?yàn)闆]有實(shí)際的業(yè)務(wù)需求,系統(tǒng)的內(nèi)容提供者用的比較多羊始,所以具體也不知道該如何記錄ContentProvider
<meta charset="utf-8">
最后
一點(diǎn)題外話:
最近面試被懟了旱幼?缺面試題刷提升自己嗎?
點(diǎn)擊:
《Android學(xué)習(xí)PDF+架構(gòu)視頻+面試文檔+源碼筆記》
來獲取學(xué)習(xí)資料提升自己去挑戰(zhàn)一下BAT面試難關(guān)吧
當(dāng)程序員容易突委,當(dāng)一個優(yōu)秀的程序員是需要不斷學(xué)習(xí)的柏卤,從初級程序員到高級程序員,從初級架構(gòu)師到資深架構(gòu)師匀油,或者走向管理缘缚,從技術(shù)經(jīng)理到技術(shù)總監(jiān),每個階段都需要掌握不同的能力敌蚜。早早確定自己的職業(yè)方向桥滨,才能在工作和能力提升中甩開同齡人。