Android 組件篇-[Android_YangKe]

Android_YangKe.jpg
Activity

Activity Android 四大組件之一,代表著頁面。它是整個(gè)視圖的承載,從下層往上看分別貼附著 Window、ViewGroup、View。同時(shí) Activity 接收用戶的各種手勢、觸屏事件并進(jìn)行派發(fā)。順序從 Activity 開始到 View 結(jié)束:Activity->Window->ViewGroup->View。默認(rèn) Activity 的啟動(dòng)模式為標(biāo)準(zhǔn)模式,我們可以通過 launchMode 標(biāo)簽在清單配置文件中對(duì)此進(jìn)行修改。

下面我們看 Activity 的生命周期,以及項(xiàng)目中經(jīng)常出現(xiàn)的幾個(gè)場景。

目錄

  • Activity 生命周期
  • 場景一
  • 場景二
  • 場景三
  • 場景四

Activity 生命周期

1> onCreate() 
2> onStart()
3> onResume() 
4> onPause() 
5> onStop() 
6> onRestart()
7> onDestory()

場景一
正在展現(xiàn)的 Activity 點(diǎn)擊 Home 按鍵會(huì)那些生命周期函數(shù)?
會(huì)執(zhí)行 onPause、onSaveInstanceState(非生命周期函數(shù))、onStop。當(dāng)重新點(diǎn)擊應(yīng)用圖標(biāo)時(shí)會(huì)執(zhí)行 onRestart、onStart、onResume。點(diǎn)擊Back按鍵會(huì)執(zhí)行 onPause、onStop、onDestory,當(dāng)重新點(diǎn)擊應(yīng)用圖標(biāo)時(shí)會(huì)執(zhí)行 onCreate、onStart、onResume。

場景二
現(xiàn)有兩個(gè) Activity 分別為 a,b。現(xiàn)在啟動(dòng) a?a 啟動(dòng) b?最后點(diǎn)擊 back 鍵生命周期會(huì)如何調(diào)用?

1> Activity a 會(huì)調(diào)用 onCreate、onStart、onResume。
2> Activity a 啟動(dòng) Activity b 兩者的生命周期調(diào)用順序如下:
   onPause(a)、onCreate、onStart、onResume、onSaveInstanceState(a)、
   onStop(a) 。
3> 點(diǎn)擊 back 鍵 后會(huì)調(diào)用 onPause(b)、onRestart、onStart、onResume、
   onStop(b)、onDestroy (b)。
//注:onSaveInstanceState 函數(shù)在 onPause 之后執(zhí)行(不一定都會(huì)執(zhí)行),例點(diǎn)擊 back 按鍵。

場景三
現(xiàn)有三個(gè) Activity 分別為 a1、a2、a3,其中 a2 為 singleInstance 模式,現(xiàn)在 a1 啟動(dòng) a2,a2 啟動(dòng) a3,此時(shí)呈現(xiàn)的頁面為 a3,然后點(diǎn)擊 back 按鍵頁面會(huì)如何展示?
頁面會(huì)回到 a1,如果再次點(diǎn)擊 back 鍵,頁面會(huì)回到 a2,再次點(diǎn)擊應(yīng)用會(huì)退出。
原因: Activity 由棧維護(hù),棧的特點(diǎn)是先進(jìn)后出,默認(rèn)情況下 Activity 的啟動(dòng)模式為標(biāo)準(zhǔn)模式,所以 a1 和 a3 存放在同一個(gè)任務(wù)棧中,由于 a2 的啟動(dòng)模式為 singleInstance 所以 a2 會(huì)獨(dú)占一個(gè)任務(wù)棧,也就是說當(dāng)前應(yīng)用現(xiàn)在有兩個(gè)任務(wù)棧。第一當(dāng)我們點(diǎn)擊 back 鍵時(shí) a3 所處的棧進(jìn)行出棧操作,a3 銷毀,a1 展示;再次點(diǎn)擊 a1 銷毀,當(dāng)前棧銷毀;再次點(diǎn)擊 a2 銷毀棧銷毀,最終應(yīng)用退出。

場景四
Activity 中 commit 一個(gè) Fragment,兩者分別會(huì)執(zhí)行哪些生命周期函數(shù)。
1> 首先 Activity 會(huì)執(zhí)行 onCreate 函數(shù),隨后 Fragment 會(huì)執(zhí)行 onAttach、onCreate、onCreateView、onActivityCreated、onStart,隨后 Activity 執(zhí)行 onStart、隨后 Activity 執(zhí)行 onResume,隨后 Fragment 執(zhí)行 onResume,此時(shí)頁面真正呈現(xiàn)同時(shí)可以進(jìn)行操作。
2> 點(diǎn)擊 Back 按鍵。首先 Fragment 執(zhí)行 onPause、其次 Activity 執(zhí)行 onPause;隨后 Fragment 執(zhí)行 onStop、Activity 執(zhí)行 onStop;最后 Fragment 執(zhí)行 onDestoryView、onDestory、onDetach,Activity 執(zhí)行 onDestory 函數(shù)。
3> 點(diǎn)擊 Home 按鍵。Fragment 執(zhí)行 onPause,Activity 執(zhí)行 onPause,F(xiàn)ragment 執(zhí)行 onStop,Activity 執(zhí)行 onStop 函數(shù)。

SingleTask 與 SingleInstance 區(qū)別?
Activity 由棧進(jìn)行維護(hù)。SingleTask 模式的 Activity 可以與非 SingleInstance 模式的 Activity 在一個(gè)任務(wù)棧共存。 而 SingleInstance 模式的 Activity 則是獨(dú)占一個(gè) Activity 任務(wù)棧。同時(shí)使用場景不同:SingleTask 對(duì)應(yīng)的 Activity 一般用于做應(yīng)用主頁面,SingleInstance 對(duì)應(yīng)的 Activity 一般用于做廣告頁面。

如何啟動(dòng)其他應(yīng)用的 Activity?

1> 創(chuàng)建 Intent 對(duì)象
   Intent intent = new Intent();
2> 配置 Intent
   //包名,包名+類名(全路徑)
   intent.setClassName("com.linxcool", "com.linxcool.PlaneActivity"));
3> 調(diào)用 startActivity 函數(shù)

Activity 的啟動(dòng)過程?
首先 Activity 的啟動(dòng)分為兩種方式:

  • 通過 launcher 進(jìn)程啟動(dòng)
  • 通過 startActivity 啟動(dòng)

前者:launcher 應(yīng)用與 ActivityManagerServer(AMS)通信,告知 AMS 我要啟動(dòng)一個(gè) Activity,系統(tǒng) fork 出進(jìn)程,執(zhí)行 Java main 函數(shù),創(chuàng)建 ActivityThread,實(shí)例化 Application,開啟消息循環(huán),創(chuàng)建 Activity,效驗(yàn) Activity 合法性,啟動(dòng) Activity,加載 xml 布局,執(zhí)行 View 的 onMeasure、onLayout、onDraw 函數(shù),最終視圖呈現(xiàn)。

后者:由 Instrumentation 對(duì)象效驗(yàn) Activity 的合法性,視情況創(chuàng)建 Activity 實(shí)例,回調(diào) Activity 的 onCreate 函數(shù),加載 xml 布局文件,執(zhí)行 View 的 onMeasure、onLayout、onDraw 函數(shù),最終視圖呈現(xiàn)。

onNewIntent 調(diào)用時(shí)機(jī)?
一般常見于非標(biāo)準(zhǔn)啟動(dòng)模式的 Activity 中。舉個(gè)例子:當(dāng) Activity 的啟動(dòng)模式為 SingleTask 時(shí),同時(shí)任務(wù)棧中有此 Activity 的實(shí)例我們?cè)俅螁?dòng)此 Activity 時(shí),此 Activity 的實(shí)例不會(huì)重新創(chuàng)建,只會(huì)執(zhí)行 onNewIntent 函數(shù),然后執(zhí)行 onRestart、onStart、onResume 函數(shù)。注:一般情況下 onNewIntent 函數(shù)是不會(huì)被觸發(fā)的。。
總結(jié):onNewIntent 在 onRestart 函數(shù)之前執(zhí)行,大多數(shù)情況下并不會(huì)被觸發(fā),只有 Activity 的啟動(dòng)模式被我們主動(dòng)修改了才會(huì)主動(dòng)調(diào)用,同時(shí)此 Activity 實(shí)例必須在任務(wù)棧中已經(jīng)存在。


Service

談?wù)?Service 的生命周期?
Service 啟動(dòng)分為兩種方式,分別為:

  • startService
  • bindService
    前者生命周期:
    onCreate->onStartCommand->onDestory
    后者生命周期:
    onCreate->onBind->onUnbind->onDestory

下面我們看兩個(gè)場景:
場景一
一個(gè) Service 通過 startService 啟動(dòng)后,調(diào)用 bindService 只會(huì)觸發(fā) onBind 函數(shù),當(dāng)被綁定的 Activity 銷毀時(shí)只會(huì)調(diào)用 onUnbind 函數(shù)。我們也可以通過調(diào)用 unbindService 與此 Service 解除綁定。注:onDestory 函數(shù)并沒有被調(diào)用,如果想要銷毀此 Service 我們必須主動(dòng)調(diào)用 stopService。

場景二
一個(gè) Service 通過 bindService 啟動(dòng)后,再次調(diào)用 startService 只會(huì)調(diào)用 onStartCommand 函數(shù),我們調(diào)用 stopService 函數(shù)并不會(huì)觸發(fā)任何 Service 的生命周期函數(shù),我們可以主動(dòng)調(diào)用 unbindService 函數(shù)進(jìn)行解綁,需要注意的是 onDestory 函數(shù)并不會(huì)執(zhí)行。我們 Activity 被銷毀只會(huì)觸發(fā) Unbind 函數(shù),onDestory 函數(shù)同樣不會(huì)被觸發(fā)。如果想要真正的停止掉這個(gè) Service 我們可以通過主動(dòng)調(diào)用 stopService 函數(shù)。

Service 兩種啟動(dòng)方式及區(qū)別
  • startService
  • bindService

前者:
生命周期函數(shù)執(zhí)行順序:onCreate->onStartCommand->onDestory

startService 函數(shù)調(diào)用兩次 Service 并不會(huì)重新創(chuàng)建,只會(huì)執(zhí)行 onStartCommand 函數(shù),如果所在的 Activity 銷毀并不會(huì)影響 Service 的正常運(yùn)行,我們可以通過 stopService 函數(shù)來主動(dòng)停止此 Service,一般用于 Activity 與 Service 通信較少的情況。

后者:
生命周期函數(shù)執(zhí)行順序:onCreate->onBind->onUnbind->onDestory

bindService 函數(shù)調(diào)用只會(huì)執(zhí)行 onCreate、onBind 函數(shù),當(dāng)我們?cè)俅握{(diào)用不會(huì)觸發(fā) Service 的任何生命周期函數(shù)。Service 的存亡與 Activity 綁定,換個(gè)說法就是當(dāng) Activity 銷毀時(shí) Service 會(huì)一并停止,我們也可以通過 unbindService 函數(shù)來主動(dòng)停止此 Service,一般用于 Activity 與 Service 與 Activity 通信頻繁場景。

一個(gè) Activty 先 start 一個(gè) Service 后,再 bind 時(shí)會(huì)回調(diào)什么方法?此時(shí)如何做才能回調(diào) Service 的 onDestory 方法?
startService 會(huì)執(zhí)行 onCreate、onStartCommand,此時(shí)如果調(diào)用 bindService 函數(shù)會(huì)調(diào)用 onBind 函數(shù)。我們先 unBindService 接著調(diào)用 stopService 就可以觸發(fā) Service 的 onDestory 函數(shù),或者先調(diào)用 stopService 函數(shù)然后接著調(diào)用 unBindService 函數(shù)。

Service 與 Activity 如何通信?
1> 使用 bindService 的形式,bindService 函數(shù)中傳入要 ServiceConnection 對(duì)象,從此對(duì)象的 onServiceConnected 函數(shù)中獲取 Service 中的 IBinder 對(duì)象,進(jìn)行通信。
2> 廣播。
3>其他第三方庫。

IntentService?
IntentService 繼承自 Service 并處理異步請(qǐng)求的一個(gè)類,在 IntentService 內(nèi)部有一個(gè)工作線程來處理耗時(shí)操作,當(dāng)任務(wù)執(zhí)行結(jié)束后 IntentService 會(huì)自動(dòng)停止服務(wù)。如果 IntentService 啟動(dòng)多次,每一個(gè)耗時(shí)任務(wù)會(huì)以工作隊(duì)列的形式在其 onHandleIntent 函數(shù)中回調(diào)執(zhí)行,依次執(zhí)行直到執(zhí)行結(jié)束。

如何將 Service 改為前臺(tái)服務(wù)?
前臺(tái)服務(wù)是一種特殊的服務(wù),它的特點(diǎn)是優(yōu)先級(jí)很高,當(dāng)系統(tǒng)內(nèi)存比較低時(shí) Android 系統(tǒng)也不會(huì)回收此類型服務(wù)。

舉個(gè)例子:如果我們?cè)?Service 中播放音樂,由于設(shè)備內(nèi)存較低觸發(fā)了 gc 突然 Service 被系統(tǒng)殺掉,但我們通過某種技術(shù)又將 Service 拉起重新進(jìn)行音樂,可想而知這種體驗(yàn)是相對(duì)不好的。那么如何解決此問題發(fā)生呢?答案是將 Service 修改為前臺(tái)服務(wù)。

如何開啟?通過在 Service 的 onStartCommand 函數(shù)中調(diào)用 startForeground 函數(shù)。如何關(guān)閉?通過在 Service 的 onDestroy 函數(shù)中調(diào)用 stopForeground 函數(shù)。需要注意的是,如果我們將服務(wù)的優(yōu)先級(jí)調(diào)整為前臺(tái),系統(tǒng)會(huì)強(qiáng)制在通知欄給用戶一個(gè)提示。我們來看下 startForeground。

   /**
     * @param id The identifier for this notification as per
     * {@link NotificationManager#notify(int, Notification)
     * NotificationManager.notify(int, Notification)}; must not be 0.
     * @param notification The Notification to be displayed.
     * 
     * @see #stopForeground(boolean)
     */
    public final void startForeground(int id, Notification notification) {
        try {
            mActivityManager.setServiceForeground(
                    new ComponentName(this, mClassName), mToken, id,
                    notification, 0);
        } catch (RemoteException ex) {
        }
    }
  • id 通知標(biāo)識(shí)符
  • notification 要展示在通知欄的具體對(duì)象

通過上面我們可以發(fā)現(xiàn)此函數(shù)接受兩個(gè)參數(shù)一個(gè)是用于通知的對(duì)象(notification),一個(gè)是通知的一個(gè)標(biāo)識(shí)。也就是說我們想要開啟前臺(tái)服務(wù),就必須在通知欄強(qiáng)制彈出一個(gè)通知。


Broadcast

廣播有幾種形式?什么特點(diǎn)?
廣播按照注冊(cè)方式可以分為兩種類型:

  • 本地廣播
  • 系統(tǒng)廣播(全局廣播)

本地廣播
本地廣播的特點(diǎn)是廣播由應(yīng)用本身發(fā)送,發(fā)送的廣播只能在應(yīng)用內(nèi)接受,其他應(yīng)用無法收到本發(fā)出的廣播,安全性更強(qiáng),性能更高。

系統(tǒng)廣播
系統(tǒng)廣播可以被任意應(yīng)用接收,性能和安全性相對(duì)本地廣播而言較低。系統(tǒng)廣播注冊(cè)方式分為兩種,分別為動(dòng)態(tài)注冊(cè)和靜態(tài)注冊(cè)。

廣播按照順序可以分為:

  • 有序廣播
  • 無序廣播

有序廣播的特點(diǎn)是,廣播的接收是有優(yōu)先級(jí)的,優(yōu)先級(jí)高的廣播可以最先接受到廣播。如果優(yōu)先級(jí)高的廣播接收器收到廣播后進(jìn)行了截?cái)?,則后續(xù)廣播接收器無法繼續(xù)收到廣播。例:現(xiàn)在有 br1、br2、br3 三個(gè)廣播接收器,其中 br1 優(yōu)先級(jí)最高、br2 其次、br3 最低,如果此時(shí) br1 接收到廣播后調(diào)用了 abortBroadcast 函數(shù),后續(xù) br2 和 br3 則無法收到應(yīng)用發(fā)出的有序廣播。

其他種類的廣播都可以成為無序廣播,這里就不在做介紹。

廣播的注冊(cè)方式?

  • 動(dòng)態(tài)注冊(cè)
  • 靜態(tài)注冊(cè)

動(dòng)態(tài)注冊(cè):
使用 Java 代碼進(jìn)行注冊(cè),一般在 onCreate 函數(shù)中進(jìn)行注冊(cè),onDestory 函數(shù)進(jìn)行解除注冊(cè)。廣播接收器的生命周期常伴隨應(yīng)用的生命周期,動(dòng)態(tài)注冊(cè)的廣播可控性更強(qiáng),優(yōu)先級(jí)相對(duì)靜態(tài)注冊(cè)而言更高。

靜態(tài)注冊(cè):
在 xml 中進(jìn)行注冊(cè)的廣播,靜態(tài)注冊(cè)是常駐型 ,也就是說當(dāng)應(yīng)用程序關(guān)閉后,如果有信息廣播來,程序仍會(huì)被系統(tǒng)調(diào)用運(yùn)行,生命周期更長。例:監(jiān)測開機(jī)廣播。

總結(jié):
廣播按照注冊(cè)方式可以分為兩種分別為:動(dòng)態(tài)注冊(cè),靜態(tài)注冊(cè)。按照廣播類型可以分為:系統(tǒng)廣播,應(yīng)用內(nèi)廣播 or 普通廣播和有序廣播。動(dòng)態(tài)注冊(cè)的廣播生命周期一般伴隨應(yīng)用的生命周期,優(yōu)先級(jí)比較高;靜態(tài)注冊(cè)的廣播反之。有序廣播和無序廣播的區(qū)別是有序廣播是同步進(jìn)行的,有先后順序,無序廣播反之。


ContentProvider

ContentProvider 存在的意義及作用?
為了在應(yīng)用程序之間交換數(shù)據(jù),Android 提供了ContentProvider,它是不同應(yīng)用程序之間進(jìn)行數(shù)據(jù)交換的標(biāo)準(zhǔn) API。當(dāng)一個(gè)應(yīng)用程序需要把自己的數(shù)據(jù)暴露給其他應(yīng)用程序使用時(shí),該應(yīng)用程序可以通過提供 ContentProvider 來實(shí)現(xiàn)。而其他應(yīng)用程序需要使用這些數(shù)據(jù)時(shí),不管提供數(shù)據(jù)的應(yīng)用程序是否啟動(dòng),我們都可以通過 ContentResolver 來操作 ContentProvider 暴露的數(shù)據(jù)。其中包括增加數(shù)據(jù) insert、刪除數(shù)據(jù) delete、修改數(shù)據(jù) update、查詢數(shù)據(jù) query 等。雖然大部分使用 ContentProvider 操作的數(shù)據(jù)都來自于數(shù)據(jù)庫,但是也可以來自于文件,如:SharedPreferences、XML 或網(wǎng)絡(luò)等其他存儲(chǔ)方式。

簡而言之,ContentProvider 作為 Android 四大組件之一,它的誕生主要是給不同應(yīng)用提供內(nèi)容訪問。ContentProvider 封裝了數(shù)據(jù)的跨進(jìn)程傳輸,我們可以直接使用 getContentResolver() 拿到 ContentResolver 進(jìn)行數(shù)據(jù)的增刪改查。

完~

喜歡有幫助的話: 雙擊、評(píng)論、轉(zhuǎn)發(fā),動(dòng)一動(dòng)你的小手讓更多的人知道!關(guān)注 Android_YangKe

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容