Android四大組件的作用及多進(jìn)程的開啟

一舶胀、Android四大組件

Android四大組件除了BroadcastReceiver以外坝锰,其他三種組件都必須在AndroidManifest中注冊岸梨,對于BroadcastReceiver來說抒蚜,既可以在AndroidManifest中注冊涮总,也可以通過代碼來注冊寻歧。在調(diào)用方式上掌栅,Activity熄求、Service和BroadcastReceiver需要借助Intent,而ContentProvider無須借助Intent弟晚。

二逾苫、Activity

Activity 是一種展示型組件,其作用就在于向用戶直接展示一個界面枚钓,并且接收用戶操作信息從而進(jìn)行交互。Activity 是唯一一種可以直接感知的組件星掰,可以說,在用戶看來 Activity 就是一個Android應(yīng)用的全部嫩舟。

1. 啟動方式

Activity 啟動方式有兩種氢烘,顯式啟動和隱式啟動

  • 顯示啟動:明確指定一個 Activity 組件
Intent intent=new Intent(this,SampleActivity.class);
startActivity(intent);
  • 隱式啟動:指向一個或多個 Activity 組件,需要我們再 AndroidManifest 中為 Activity 配置 intent-filter
Intent intent=new Intent("com.wuc.sampleActivity");
startActivity(intent);
<activity android:name=".SampleActivity">
    <intent-filter>
        <action android:name="com.wuc.sampleActivity"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>
2. 生命周期

(1)正常情況下播玖,Activity 會經(jīng)歷如下生命周期

  • onCreate:表示 Activity 正在被創(chuàng)建饭于。在這個方法中可以做一些初始化操作,比如調(diào)用 setContentView 去加載界面布局資源果覆,初始化 Activity 所需數(shù)據(jù)等殖熟。
  • onRestart:表示 Activity 正在重新啟動。當(dāng)當(dāng)前 Activity 從不可見重新變?yōu)榭梢姞顟B(tài)時燎猛,onRestart 就會被調(diào)用照皆。這種情形一般是用戶行為導(dǎo)致沸停,比如用戶按 Home 健切換桌面或者用戶打開了一個新的 Activity,這時當(dāng)前 Activity 就會暫停瘟滨,也就是 onPause 和 onStop 被執(zhí)行了能颁,接著用戶又回到這個 Activity伙菊,就會出現(xiàn)這種情況敌土。
  • onStart:表示 Activity 正在被啟動,即將開始运翼,這時 Activity 已經(jīng)可見了,但還沒有出現(xiàn)在前臺矩欠,還無法和用戶交互悠夯。這個時候可以理解為 Activity 已經(jīng)顯示出來了沦补,但我們還看不到。
  • onResume:表示 Activity 已經(jīng)可見了栓袖,并且出現(xiàn)在前臺并開始活動店诗。要注意這個和 onStart 的對比,onStart 和 onResume 都表示 Activity 已經(jīng)可見捧弃,但是 onStart 的時候 Activity 還在后臺擦囊,onResume 的時候 Activity 才顯示到前臺瞬场。
  • onPause:表示 Activity 正在停止,正常情況下眼五,緊接著 onStop 就會被調(diào)用彤灶。在特殊情況下,如果這個時候快速的在回到當(dāng)前 Activity诵姜,那么 onResume 會被調(diào)用搏熄,但這種情況很難重現(xiàn)。此時可以做一些存儲數(shù)據(jù)瑟俭、停止動畫等工作摆寄,但不能太耗時,因為這會影響到新 Activity 的顯示逗扒,onPause 必須先執(zhí)行完欠橘,新 Activity 的 onResume 才會執(zhí)行。
  • onStop:表示 Activity 即將停止黍檩,可以做一些稍微重量級的回收工作始锚,但不能太耗時瞧捌。
  • onDestroy:表示 Activity 即將被銷毀,這是 Activity 生命周期最后一個回調(diào)殿怜,可以做一些回收工作和最終的資源釋放曙砂。

下圖詳細(xì)的描述了 Activity 各種生命周期的切換過程:

Activity 的生命周期切換過程.png

三鸠澈、Service

Service主要用于在后臺執(zhí)行一系列計算任務(wù),耗時的后臺任務(wù),需要單獨的線程去完成新锈,因為Service本身是運(yùn)行在主線程的眶熬。Service不與用戶產(chǎn)生UI交互,其他的應(yīng)用組件可以啟動Service拳缠,即便用戶切換了其他應(yīng)用窟坐,啟動的Service仍可在后臺運(yùn)行。
1. Context.startService()啟動
被啟動的服務(wù)的生命周期:onCreate -> onStartCommand -> onDestroy

  • 如果Service被startService方法啟動多次臣疑,其中只會調(diào)用一次onCreate方法徙菠,但是會調(diào)用多次onStartCommand婿奔,此時系統(tǒng)只會創(chuàng)建一個Service實例,因此只需要調(diào)用一次stopService方法就可以停掉服務(wù)挤茄。
  • 如果Service被某個Activity 調(diào)用startService方法啟動记餐,不管是否有Activity使用bindService綁定或unbindService解除綁定到該Service,該Service都在后臺運(yùn)行囚衔。
  • startService啟動的Service將會一直在后臺運(yùn)行练湿,而不管對應(yīng)程序的Activity是否在運(yùn)行审轮,直到被調(diào)用stopService、或自身的stopSelf方法篡诽、或系統(tǒng)資源不足android系統(tǒng)也可能結(jié)束該服務(wù)榴捡。

2.bindService
被綁定的服務(wù)的生命周期:onCreate-> onBind-> onUnbind->onDestory()

  • 如果Service被某個Activity調(diào)用bindService方法綁定啟動,不管調(diào)用bindService幾次达椰,只會調(diào)用一次onCreate方法啰劲,同時始終不會調(diào)用onStartCommand方法。
  • 當(dāng)連接建立之后廷支,Service將會一直運(yùn)行酥泞,除非調(diào)用unbindService斷開連接啃憎、或之前調(diào)用bindService的Context 不存在了,如Activity被finish的時候悯姊,系統(tǒng)將會自動停止Service贩毕,對應(yīng)的將被調(diào)用onDestroy方法辉阶。

3. startService和bindService混合使用
需求場景:在activity中要得到service對象進(jìn)而能調(diào)用對象的方法,但同時又不希望activity finish的時候service也被destory了垃僚。

  • 先startService谆棺,后bindService

1罕袋、先調(diào)用startService,后調(diào)用bindService朵夏。服務(wù)的執(zhí)行過程為:

onCreate —》onStartCommand —》onStart —》onBind  —》(onServiceConnected)

2榆纽、先unBindService,后stopService。服務(wù)結(jié)束的執(zhí)行過程:

onUnbind —》onDestroy

注意:unBindService會執(zhí)行到onUnbind唠摹,stopService會執(zhí)行到onDestroy勾拉。
3、先stopService成肘,后unBindService斧蜕。服務(wù)結(jié)束的執(zhí)行過程:

onUnbind —》onDestroy

注意:stopService不會執(zhí)行任何操作批销,unBindService會執(zhí)行到onUnbind—》onDestroy。

  • 先bindService丘逸,后startService

1深纲、先調(diào)用startService劲妙,后調(diào)用bindService。服務(wù)的執(zhí)行過程為:

onCreate —》onBind  —》(onServiceConnected) —》onStartCommand —》onStart

2涛舍、先unBindService富雅,后stopService肛搬。服務(wù)結(jié)束的執(zhí)行過程:

onUnbind —》onDestroy

注意:unBindService會執(zhí)行到onUnbind温赔,stopService會執(zhí)行到onDestroy。
3啤贩、先stopService,后unBindService章郁。服務(wù)結(jié)束的執(zhí)行過程:

onUnbind —》onDestroy

注意:stopService不會執(zhí)行任何操作暖庄,unBindService會執(zhí)行到onUnbind—》onDestroy楼肪。

總結(jié):
1春叫、若被停止的服務(wù)依然有ServiceConnection 與其綁定,則服務(wù)不能銷毀蔬将,直至我們把所有ServiceConnection 解綁
2央星、當(dāng)所有ServiceConnection 解綁后莉给,系統(tǒng)會自動銷毀服務(wù)。(不包括同時用startService()啟動的情況徐矩。此時叁幢,我們不得不再調(diào)用一次stopService來銷毀它)
3曼玩、多次bindService時,服務(wù)本身的onBind不會被多次執(zhí)行豫尽。
4顷帖、bind上一個Service后渤滞,執(zhí)行一次unBindService就夠了妄呕。不然會出錯录肯。
5、一個App里论咏,同一個Activity多次bind一個服務(wù)厅贪,除了第一次雅宾,后面的bind不會有任何onBind眉抬、onServiceConnected打印。
一個App里悄谐,不同的Activity去bind一個服務(wù)爬舰,第一次bind有onBind寒瓦、onServiceConnected打印杂腰,后面的bind只會有onServiceConnected打印。
6惜颇、一個Activity bind上一個Service后恤筛,如果Activity finish前沒有調(diào)用unBind毒坛,App會崩潰

四林说、BroadcastReceiver

主要用于在不同的組件乃至不同的應(yīng)用之間傳遞消息腿箩,不與用戶產(chǎn)生交互珠移,工作在系統(tǒng)內(nèi)部末融。
注冊的兩種方式:
1勾习、靜態(tài)注冊
靜態(tài)注冊是在AndroidManifest.xml文件中配置的

<receiver android:name=".MyReceiver">  
     <intent-filter>  
            <action android:name="android.intent.action.MY_BROADCAST"/>  
            <category android:name="android.intent.category.DEFAULT" />  
     </intent-filter>  
</receiver> 

配置了以上信息之后巧婶,只要是android.intent.action.MY_BROADCAST這個地址的廣播,MyReceiver都能夠接收的到英岭。注意诅妹,這種方式的注冊是常駐型的诅需,也就是說當(dāng)應(yīng)用關(guān)閉后堰塌,如果有廣播信息傳來,MyReceiver也會被系統(tǒng)調(diào)用而自動運(yùn)行般此。
2铐懊、動態(tài)注冊
動態(tài)注冊需要在代碼中動態(tài)的指定廣播地址并注冊瞎疼,通常我們是在Activity或Service注冊一個廣播

MyReceiver receiver = new MyReceiver();  
          
IntentFilter filter = new IntentFilter();  
filter.addAction("android.intent.action.MY_BROADCAST");  
          
registerReceiver(receiver, filter); 

注意贼急,registerReceiver是android.content.ContextWrapper類中的方法,Activity和Service都繼承了ContextWrapper空闲,所以可以直接調(diào)用碴倾。在實際應(yīng)用中,我們在Activity或Service中注冊了一個BroadcastReceiver跌榔,當(dāng)這個Activity或Service被銷毀時如果沒有解除注冊异雁,系統(tǒng)會報一個異常,提示我們是否忘記解除注冊了僧须。所以片迅,記得在特定的地方執(zhí)行解除注冊操作:

@Override  
protected void onDestroy() {  
    super.onDestroy();  
    unregisterReceiver(receiver);  
}

注意,這種注冊方式與靜態(tài)注冊相反皆辽,不是常駐型的,也就是說廣播會跟隨程序的生命周期芥挣。
當(dāng)注冊完成之后驱闷,這個接收者就可以正常工作了。我們可以用以下方式向其發(fā)送一條廣播:

Intent intent = new Intent("android.intent.action.MY_BROADCAST");  
intent.putExtra("msg", "hello receiver.");  
sendBroadcast(intent);

注意空另,sendBroadcast也是android.content.ContextWrapper類中的方法,它可以將一個指定地址和參數(shù)信息的Intent對象以廣播的形式發(fā)送出去蹋砚。

五扼菠、ContentProvider

ContentProvider是一種數(shù)據(jù)共享型組件,用于向其他組件乃至其他應(yīng)用共享數(shù)據(jù)

  • ContentProvider 封裝了數(shù)據(jù)的跨進(jìn)程傳輸坝咐,我們可以直接使用 getContentResolver() 拿到 ContentResolver 進(jìn)行增刪改查即可循榆。
  • ContentProvider 以一個或多個表(與在關(guān)系型數(shù)據(jù)庫中的表類似)的形式將數(shù)據(jù)呈現(xiàn)給外部應(yīng)用。 行表示提供程序收集的某種數(shù)據(jù)類型的實例墨坚,行中的每個列表示為實例收集的每條數(shù)據(jù)秧饮。

實現(xiàn)一個 ContentProvider 時需要實現(xiàn)以下幾個方法:

  • onCreate():初始化 provider
  • query():查詢數(shù)據(jù)
  • insert():插入數(shù)據(jù)到 provider
  • update():更新 provider 的數(shù)據(jù)
  • delete():刪除 provider 中的數(shù)據(jù)
  • getType():返回 provider 中的數(shù)據(jù)的 MIME 類型

注意:
1、onCreate() 默認(rèn)執(zhí)行在主線程泽篮,別做耗時操作盗尸,query() 也最好異步執(zhí)行
2、上面的 4 個增刪改查操作都可能會被多個線程并發(fā)訪問帽撑,因此需要注意線程安全

ContentProvider 與 URI

ContentProvider 使用 URI 標(biāo)識要操作的數(shù)據(jù)泼各,這里的內(nèi)容 URI 主要包括兩部分:
1、authority:整個提供程序的符號名稱
2亏拉、path:指向表的名稱/路徑
內(nèi)容 URI 統(tǒng)一的形式就是:

content://authority/path

如:

content://user_dictionary/words

當(dāng)調(diào)用 ContentResolver 方法來訪問 ContentProvider 中的表時扣蜻,需要傳遞要操作表的 URI逆巍。

在通過 ContentResolver 進(jìn)行數(shù)據(jù)請求時(比如 contentResolver.insert(uri, contentValues);), 系統(tǒng)會檢查指定 URI 的 authority 信息弱贼,然后將請求傳遞給注冊監(jiān)聽這個 authority 的 ContentProvider 蒸苇。這個 ContentProvider 可以監(jiān)聽 URI 想要操作的內(nèi)容,Android 中為我們提供了 UriMatcher 來解析 URI吮旅。

六溪烤、開啟多進(jìn)程

在Android中使用多進(jìn)程的方法,那就是在AndroidManifest中給四大組件(Activity,Service,Receiver,ContentProvider)指定android:process屬性
process屬性的值可以隨便設(shè)置

<activity   
      android:name="com.wuc.sample.SecondActivity"  
      android:process=":second" />  
<activity   
      android:name="com.wuc.sample.ThirdActivity"  
      android:process="com.wuc.sample.third" /> 

假設(shè)包名是:com.wuc.sample
1、":"的含義是指要在當(dāng)前的進(jìn)程名前面附加上當(dāng)前的包名,對于SecondActivity來說,它的完整的進(jìn)程名為"com.wuc.sample:second"庇勃。對于ThirdActivity中的聲明方式,它是一種完整的命名方式,不會附加包名信息;
2檬嘀、以":"開頭的進(jìn)程屬于當(dāng)前應(yīng)用的私有進(jìn)程,其他應(yīng)用的組件不可以和它跑在同一個進(jìn)程中;而進(jìn)程名不以":"開頭的進(jìn)程屬于全局進(jìn)程,其他應(yīng)用通過ShareUID方式可以和它跑在同一個進(jìn)程中责嚷。

Android系統(tǒng)為每個應(yīng)用分配一個唯一的UID鸳兽,具有相同UID的應(yīng)用才能共享數(shù)據(jù)。兩個應(yīng)用通過ShareUID跑在同一個進(jìn)程中是有要求的罕拂,需要這兩個應(yīng)用有相同的ShareUID并且簽名相同才可以揍异。在這種情況下,它們可以互相訪問對方的私有數(shù)據(jù)爆班,比如data目錄衷掷,組件信息等。
如果它們跑在同一個進(jìn)程中,那么除了能共享data目錄,組件信息,還可以共享內(nèi)存數(shù)據(jù)等等

多進(jìn)程模式的運(yùn)行機(jī)制

SecondActivity運(yùn)行在一個單獨的進(jìn)程中柿菩,Android為每一個應(yīng)用程序分配了一個獨立的虛擬機(jī)戚嗅,或者說為每個進(jìn)程都分配了一個獨立的虛擬機(jī),不同的虛擬機(jī)在內(nèi)存分配上 有不同的地址空間枢舶,這就會導(dǎo)致在不同的虛擬機(jī)中訪問同一類的對象會產(chǎn)生多份副本懦胞。在一個進(jìn)程中修改某個值只會影響當(dāng)前進(jìn)程,對其他進(jìn)程不會造成任何影響凉泄。
所有運(yùn)行在不同進(jìn)程中的四大組件躏尉,只要它們之間如要通過內(nèi)存來共享數(shù)據(jù),都會失敗旧困,這也是多進(jìn)程所帶來的主要影響醇份。

一般來說,使用多進(jìn)程會造成如下幾方面的問題:

  • 靜態(tài)成員和單例模式完全失效 (不是同一塊內(nèi)存吼具,會產(chǎn)生不同的副本)
  • 線程同步機(jī)制完全失效 (不是同一塊內(nèi)存僚纷,所以對象也不是同一個,因此類鎖拗盒、對象鎖也不是同一個怖竭,不能保證線程同步)
  • SharedPreferences 的可靠性下降 (SharedPreferences不支持多個進(jìn)程同時寫,會有一定的幾率丟失數(shù)據(jù))
  • Application會多次創(chuàng)建(Android為每個進(jìn)程分配獨立的虛擬機(jī)陡蝇,這個過程其實就是啟動一個應(yīng)用痊臭,所以Application會被創(chuàng)建多次)哮肚,所以我們不能直接將一些數(shù)據(jù)保存在Application中。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末广匙,一起剝皮案震驚了整個濱河市允趟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鸦致,老刑警劉巖潮剪,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異分唾,居然都是意外死亡抗碰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門绽乔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弧蝇,“玉大人,你說我怎么就攤上這事折砸】戳疲” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵睦授,是天一觀的道長鹃觉。 經(jīng)常有香客問我,道長睹逃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任祷肯,我火速辦了婚禮沉填,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘佑笋。我一直安慰自己翼闹,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布蒋纬。 她就那樣靜靜地躺著猎荠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜀备。 梳的紋絲不亂的頭發(fā)上关摇,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機(jī)與錄音碾阁,去河邊找鬼输虱。 笑死,一個胖子當(dāng)著我的面吹牛脂凶,可吹牛的內(nèi)容都是我干的宪睹。 我是一名探鬼主播愁茁,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亭病!你這毒婦竟也來了鹅很?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤罪帖,失蹤者是張志新(化名)和其女友劉穎促煮,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胸蛛,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡污茵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了葬项。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泞当。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖民珍,靈堂內(nèi)的尸體忽然破棺而出襟士,到底是詐尸還是另有隱情,我是刑警寧澤嚷量,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布陋桂,位于F島的核電站,受9級特大地震影響蝶溶,放射性物質(zhì)發(fā)生泄漏嗜历。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一抖所、第九天 我趴在偏房一處隱蔽的房頂上張望梨州。 院中可真熱鬧,春花似錦田轧、人聲如沸暴匠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽每窖。三九已至,卻和暖如春弦悉,著一層夾襖步出監(jiān)牢的瞬間窒典,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工稽莉, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留崇败,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像后室,于是被迫代替她去往敵國和親缩膝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容