對于Activity的啟動流程,我們已經有了幾個版本的分析了。這里我們分析一個更容易一些的,四大組件中最簡單的Broadcast Receiver。

創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供根河網站建設、根河做網站、根河網站設計、根河網站制作等企業(yè)網站建設、網頁設計與制作、根河企業(yè)網站模板建站服務,10年根河做網站經驗,不只是建網站,更提供有價值的思路和整體網絡服務。
關于Broadcast,有幾點需要了解。首先是廣播的類型,然后是廣播的發(fā)送方法,最后是廣播是如何被接收的。這三者相輔相承的,比如普通廣播和有序廣播只有在詳細了解了廣播的接收過程了之后,才能真正明白它的含義。
普通的廣播是不在意順序的,最簡單的理解是同時可以收到這個廣播。如果應用是動態(tài)注冊這個廣播的,且廣播發(fā)送時這個進程還活著,那么當然可以并發(fā)的把廣播盡快地傳送出去是最好的。
但是,如果是通過AndroidManifest.xml靜態(tài)注冊的情況,也就是說這個廣播首先要把一個進程啟動起來,這時并發(fā)啟動很多進程就是個問題了。Android目前的做法是,對這種靜態(tài)的廣播接收者,自動按有序廣播的方式來串行處理。但是這對應用是透明的,應用不能假設系統(tǒng)已經把靜態(tài)的無序廣播當成有序廣播來處理。
這個時候講粘性廣播有福了,因為從Android 5.0(API 21)開始,因為安全性的問題,官方已經正式廢棄了粘性廣播。
Context類提供兩個方法可以用于發(fā)送普通廣播:
差別是第二個設置權限。
發(fā)給特定的用戶:
有序廣播因為要處理消息的處理結果,所以要復雜一些。
如果只是想讓廣播可以按優(yōu)先級來收取,并不在意處理的結果,可以用下面的版本:
同樣,在多用戶環(huán)境下,也可以選擇給哪個用戶發(fā)廣播:
不管是普通的還是有序的廣播都對應有粘性的版本:
以上的API都是定義于Context類中:
首先我們先看看發(fā)送端是如何發(fā)送的。
我們首先先放一個大圖,讓大家先有一個直觀的印象,不管普通廣播、有序廣播、粘性廣播如何組合,最終都匯集到一個大方法中。
我們先看應用發(fā)送普通廣播的一個簡單的例子:
非常簡單,調用ContentWrapper的sendBroadcast方法就可以了。
然后我們順藤摸瓜就好了。
Activity中的sendBroadcast,實際上調用的是:
我們來看frameworks/base/core/java/android/content/ContextWrapper.java中對sendBroadcast的定義:
ContextWrapper只是一個包裝,真正的實現(xiàn)在ContextImpl中
我們來看/frameworks/base/core/java/android/app/ContextImpl.java中真正實現(xiàn)sendBroadcast的功能:
它會通過IPC去調用AMS的broadcastIntent。由于我們這個普通的廣播的方法參數(shù)最少,所以好多都是傳null。
加鎖,定參數(shù),然后調用真正的邏輯的實現(xiàn)。
我們先把broadcastIntentLocked的真正邏輯放一下,先看看有序廣播是如何發(fā)送的。
ContextWrapper.sendOrderedBroadcast
Context是abstract方法,調用的是ContextWrapper的實現(xiàn):
跟普通廣播一樣,還是會調用到ContextImpl.sendOrderedBroadcast
有序廣播調用broadcastIntent的區(qū)別在于serialized參數(shù),普通廣播為false,有序廣播為true.
原型為:
前面講過帶有回調的版本,我們看看它是如何實現(xiàn)的:
當然還是調用ContextImpl.sendOrderedBroadcast
這次變成只是一個封裝了,它會調用一個更多參數(shù)的版本:
這次是一個全參數(shù)調用broadcastIntent的版本了,除了sticky就齊了
我們也不繞圈子了,直接看ContextImpl.sendStickyBroadcast.
Android中的廣播機制可以分為標準廣播和有序廣播兩種類型。
標準廣播是一種完全異步執(zhí)行的廣播,在廣播發(fā)出去之后,所有的廣播接收器幾乎同時接收到這條廣播消息,它們之間沒有任何項目順序可言。這種廣播的效率比較高,但也意味著它是無法被截斷的。工作流程如圖:
有序廣播是一種同步執(zhí)行的廣播,在廣播發(fā)出之后,同一時刻只會有一個廣播接收器能夠收到這條廣播消息,當這個廣播接收器中的邏輯執(zhí)行完畢后,廣播才會繼續(xù)傳遞。此時的廣播接收器是有先后順序,優(yōu)先級高的廣播接收器就可以先收到廣播消息,并且前面的廣播接收器還可以截斷正在傳遞的廣播,這樣后面的廣播接收器就無法收到廣播消息了。工作流程如圖:
BroadcastReceiver(廣播接收器)是Android四大組件之一,顧名思義,通過廣播的方式進行消息傳遞,其本質是一個全局的監(jiān)聽器,可以監(jiān)聽到各種廣播,可以用來實現(xiàn)不同組件之間的通信。廣播最大的特點就是發(fā)送方并不關心接收方是否接到數(shù)據,也不關心接收方是如何處理數(shù)據的,通過這樣的形式來達到接、收雙方的完全解耦合。
又稱無序廣播,這種廣播完全是異步的,所有與廣播Intent匹配的BroadcastReceiver,都可以收到這條廣播,并且不分先后順序,視為同時收到,通過Context.sendBroadcast()方法發(fā)送。這種廣播的效率比較高,但缺點是接收器不能將處理結果傳遞給下一個接收器,并且無法在中途終止廣播。
這是一種同步執(zhí)行的廣播,通過Context.sendOrderedBroadcast()方法發(fā)送,這種廣播發(fā)出后,通過receiver的intent-filter中的android:priority屬性來設置優(yōu)先級,優(yōu)先級從-1000~1000,數(shù)越大,優(yōu)先級越高,使用setResult()方法把結果傳遞給下一個接收者,通過getResult()方法獲取上一個接收者傳遞過來的結果,并可以通過abortBroadcast()方法丟棄該廣播,使該廣播不再傳遞給下一個接收者。
粘性廣播通過Context.sendStickBroadcast()方法來發(fā)送,用此方法發(fā)送的廣播會一直滯留,當有匹配此廣播的接收器被注冊后,該廣播接收器就會收到此廣播。使用此廣播時,需要獲得BROADCAST_STICKY權限。(在 android 5.0/api 21后不再推薦使用)
Android系統(tǒng)中內置了多個系統(tǒng)廣播,只要涉及到手機的基本操作,基本上都會發(fā)出相應的系統(tǒng)廣播。如:開啟啟動,網絡狀態(tài)改變,拍照,屏幕關閉與開啟,點亮不足等等。每個系統(tǒng)廣播都具有特定的intent-filter,其中主要包括具體的action,系統(tǒng)廣播發(fā)出后,將被相應的BroadcastReceiver接收。系統(tǒng)廣播在系統(tǒng)內部當特定事件發(fā)生時,有系統(tǒng)自動發(fā)出。
以上廣播都屬于全局廣播,發(fā)出去的廣播,只要有匹配的接收者,就可以收到廣播。這樣一來會造成一些問題,一是消耗性能,二是容易引起安全性的問題,為了能夠簡單的解決這方面的問題,Android引入了一套廣播本地廣播機制,使用該機制發(fā)出的廣播只能夠在本應用內部進行傳遞,并且廣播接收器也只能接收來自本應用發(fā)出的廣播。
使用方法
1.注冊本地廣播接收器
2.發(fā)送本地廣播
3.注銷本地廣播接收器
本文用到的BroadcastReceiver
Android 8.0(API級別26)取消大部分靜態(tài)注冊廣播,建議使用動態(tài)廣播
兩種方式:靜態(tài)注冊和動態(tài)注冊
動態(tài)注冊:
1)動態(tài)注冊:需要定義一個繼承自BroadcastReceiver類的子類,該接收器需要在Activity中的onDestroy中注銷
2)靜態(tài)注冊:通過在AndroidManifest.xml中配置
兩種廣播形式:有序廣播和無序廣播
1)無序廣播:接受標準廣播的接收器將同時收到廣播消息,異步執(zhí)行,沒有先后順序 sendBroadCast
2)有序廣播:sendOrderedBroadCast,按照一定順序先后被接受順序,由priority屬性決定,abortBroadCast中斷廣播
如果只想在本應用中發(fā)送和接受廣播,使用LocalBroadcastReceiver來對廣播進行管理
本地廣播不支持靜態(tài)注冊
優(yōu)點 :安全高效
Service是Android中的一種組件,和Activity的級別一致,但不能自己運行,只能后臺運行,和其他組件交互,服務必須注冊才能使用
本地服務:服務依附在主線程中,節(jié)約資源,主線程死掉服務終止
遠程服務:服務在獨立進程中,靈活性好 ,占用資源高
兩種服務的啟動模式:
1)start方式:調用者和服務之間沒有關聯(lián),調用者退出不會影響服務,startService啟動服務,如果服務不存在,調用onCreat方法,然后onStartCommand被調用。stopService關閉服務,onDestroy方法被調用
2)bind方式:調用者和服務綁定,調用者退出,服務終止bindService啟動服務,onCreate方法創(chuàng)建服務,onBind方法綁定服務,onUnbind方法解綁,onDestory在服務結束時調用
以下廣播簡稱Broadcast
?? 是Android四大組件之一,在四大組件的另外兩個組件 和 擁有發(fā)送和接收廣播的能力。Android 是在 進程間通信機制的基礎上實現(xiàn)的,內部基于消息發(fā)布和訂閱的事件驅動模型,廣播發(fā)送者負責發(fā)送消息,廣播接收者需要先訂閱消息,然后才能收到消息。 進程間通信與 的區(qū)別在于:
?? 有三種類型
?? 存在一個注冊中心,也可以說是一個調度中心,即 。廣播接收者將自己注冊到 中,并指定要接收的廣播類型;廣播發(fā)送者發(fā)送廣播時,發(fā)送的廣播首先會發(fā)送到 , 根據廣播的類型找到對應的 ,找到后邊將廣播發(fā)送給其處理。
?? 這里以普通廣播為例子, 接收者有兩種注冊方式,一種是 ,一種是 :
(廣播的發(fā)送分為 兩種,這里針對有序的廣播) 中的android:priority=""和 中的IntentFilter.setPriority(int)可以用來設置廣播接收者的優(yōu)先級,默認都是0 , 范圍是[-1000, 1000],值越大優(yōu)先級越高,優(yōu)先級越高越早收到。
?? 在相同優(yōu)先級接收同個類型廣播時, 的廣播接收器比 的廣播接收者更快的接收到對應的廣播,這個之后會進行分析。
?? 注:以下源碼基于rk3399_industry Android7.1.2
?? 的流程可分為 , 和 三個部分,這里依次分析下
?? 在Android系統(tǒng)的 機制中,前面提到, 作為一個注冊和調度中心負責注冊和轉發(fā) 。所以 的注冊過程就是把它注冊到 的過程。
?? 這里我們分析 廣播的過程, 和 有一個共同的父類 ,所以它們對應的注冊過程其實是調用 ,接下來我們按照流程逐步分析調用流程的源碼。
frameworks/base/core/java/android/content/ContextWrapper.java
?? 在之前的 Android應用程序啟動入口ActivityThread.main流程分析 分析過,在我們啟動 Activity 時會創(chuàng)建一個 對象,然后通過 傳給我們啟動的 ,其內部就會將該對象賦值給 ; 的 方法也是類似的賦值流程,這里放個簡易的源碼應該更好理解
?? 可以看到最后都會將生成的 對象賦值給對應的
對象。接下來繼續(xù)分析 , 即 函數(shù)。
/frameworks/base/core/java/android/app/ContextImpl.java
?? 這里我們首先看下如何將廣播接收者 封裝成一個 接口的 本地對象
/frameworks/base/core/java/android/app/LoadedApk.java
?? 每一個注冊過廣播接收者的 或 組件在font color='Crimson' LoadedApk /font類中都有個對應的 對象,該對象負責將 與 組件關聯(lián)起來。這些對象,以關聯(lián)的 作為關鍵字保存在一個 中。之后對應的 又以 的 作為關鍵字保存在 的成員變量 對象中。最后通過 對應的 方法獲得其 接口的 本地對象。之后再回到 注冊方法內,將 對象發(fā)給 進行注冊。
/frameworks/base/core/java/android/app/ActivityManagerNative.java
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
?? 在的 或 注冊一個 時,并不是將其注冊到font color='OrangeRed'AMS/font中,而是將與它關聯(lián)的font color='OrangeRed'InnerReceiver/font對象注冊到font color='OrangeRed'AMS/font中,當font color='OrangeRed'AMS/font接收到廣播時,會根據 在內部找到對應的font color='OrangeRed'InnerReceiver/font對象,然后在通過這個對象將這個廣播發(fā)送給對應的 處理。
?? 注冊過程這邊畫了一個簡單的流程圖:
?? font color='OrangeRed'Broadcast/font的發(fā)送過程可簡單描述為以下幾個過程:
frameworks/base/core/java/android/content/ContextWrapper.java
/frameworks/base/core/java/android/app/ContextImpl.java
/frameworks/base/core/java/android/app/ActivityManagerNative.java
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
Android 中的廣播主要可以分為兩種類型:標準廣播和有序廣播
一種完全異步執(zhí)行的廣播,在廣播發(fā)出之后,所有的BroadcastReceiver幾乎會在同一時刻收到這條廣播消息,因此它們之間沒有任何先后順序可言。這種廣播的效率會比較高,但同時也意味著它是無法被截斷
標準廣播工作示意圖:
一種同步執(zhí)行的廣播,在廣播發(fā)出之后,同一時刻只會有一個BroadcastReceiver能夠收到這條廣播消息,當這個BroadcastReceiver中的邏輯執(zhí)行完畢后,廣播才會繼續(xù)傳遞。所以此時的BroadcastReceiver是有先后順序的,優(yōu)先級高的BroadcastReceiver就可以先收到廣播消息,并且前面的BroadcastReceiver還可以截斷正在傳遞的廣播,這樣后面的BroadcastReceiver就無法收到廣播消息了
有序廣播工作示意圖:
可以讓程序在未啟動的情況下接收廣播
在Android 8.0系統(tǒng)之后,所有隱式廣播都不允許使用靜態(tài)注冊的方式來接收了。隱式廣播指的是那些沒有具體指定發(fā)送給哪個應用程序的廣播,大多數(shù)系統(tǒng)廣播屬于隱式廣播,但是少數(shù)特殊的系統(tǒng)廣播目前仍然允許使用靜態(tài)注冊的方式來接收,詳見網址:
在 AndroidManifest.xml 文件中注冊
在 AndroidManifest.xml 文件中進行權限聲明
不要在 onReceive() 方法中添加過多的邏輯或者進行任何的耗時操作,因為BroadcastReceiver中是不允許開啟線程的,當 onReceive() 方法運行了較長時間而沒有結束時,程序就會出現(xiàn)錯誤
先定義一個BroadcastReceiver來準備接收此廣播
在 AndroidManifest.xml 文件中注冊
有序廣播是一種同步執(zhí)行的廣播,并且是可以被截斷的。為了驗證這一點,我們需要再創(chuàng)建一個新的BroadcastReceiver。新建AnotherBroadcastReceiver
同樣,在 AndroidManifest.xml 文件中注冊,同時,使用 intent-filter 標簽的 android:priority 屬性設置優(yōu)先級
前面的 AnotherBroadcastReceiver 的優(yōu)先級比較高,因此 AnotherBroadcastReceiver 一定比 MyBroadcastReceiver 先收到廣播,因此,可以在 AnotherBroadcastReceiver 的 onReceive 方法中使用 abortBroadcast() 方法截斷廣播,這樣 MyBroadcastReceiver 就收不到該廣播了
在界面上彈出一個對話框,讓用戶無法進行任何其他操作,必須點擊對話框中的“確定”按鈕,關閉所有的Activity,然后回到登錄界面即可
ActivityCollector 類用于管理所有的Activity,具有關閉所有Activity的功能
創(chuàng)建 BaseActivity 類作為所有 Activity 的父類,并在里面實現(xiàn)強制下線功能,在這里實現(xiàn)此功能,有以下幾點原因
創(chuàng)建一個LoginActivity來作為登錄界面
activity_login.xml
LoginActivity 如果輸入 123 就到 MainActivity界面
MainActivity 中點擊強制下線按鈕,就發(fā)送強制下線的廣播
MainActivity 布局
本文題目:android廣播接收,android廣播接收者的作用
本文網址:http://chinadenli.net/article39/dsecoph.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供標簽優(yōu)化、搜索引擎優(yōu)化、網站改版、自適應網站、面包屑導航、微信小程序
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)