先自定義一個廣播類

員工經(jīng)過長期磨合與沉淀,具備了協(xié)作精神,得以通過團隊的力量開發(fā)出優(yōu)質(zhì)的產(chǎn)品。成都創(chuàng)新互聯(lián)堅持“專注、創(chuàng)新、易用”的產(chǎn)品理念,因為“專注所以專業(yè)、創(chuàng)新互聯(lián)網(wǎng)站所以易用所以簡單”。公司專注于為企業(yè)提供成都網(wǎng)站設(shè)計、網(wǎng)站制作、微信公眾號開發(fā)、電商網(wǎng)站開發(fā),微信小程序開發(fā),軟件按需制作等一站式互聯(lián)網(wǎng)企業(yè)服務(wù)。
然后在Application中進行動態(tài)注冊
因為是動態(tài)注冊所以無需在AndroidManifest.xml中進行注冊
對于Activity的啟動流程,我們已經(jīng)有了幾個版本的分析了。這里我們分析一個更容易一些的,四大組件中最簡單的Broadcast Receiver。
關(guān)于Broadcast,有幾點需要了解。首先是廣播的類型,然后是廣播的發(fā)送方法,最后是廣播是如何被接收的。這三者相輔相承的,比如普通廣播和有序廣播只有在詳細了解了廣播的接收過程了之后,才能真正明白它的含義。
普通的廣播是不在意順序的,最簡單的理解是同時可以收到這個廣播。如果應(yīng)用是動態(tài)注冊這個廣播的,且廣播發(fā)送時這個進程還活著,那么當然可以并發(fā)的把廣播盡快地傳送出去是最好的。
但是,如果是通過AndroidManifest.xml靜態(tài)注冊的情況,也就是說這個廣播首先要把一個進程啟動起來,這時并發(fā)啟動很多進程就是個問題了。Android目前的做法是,對這種靜態(tài)的廣播接收者,自動按有序廣播的方式來串行處理。但是這對應(yīng)用是透明的,應(yīng)用不能假設(shè)系統(tǒng)已經(jīng)把靜態(tài)的無序廣播當成有序廣播來處理。
這個時候講粘性廣播有福了,因為從Android 5.0(API 21)開始,因為安全性的問題,官方已經(jīng)正式廢棄了粘性廣播。
Context類提供兩個方法可以用于發(fā)送普通廣播:
差別是第二個設(shè)置權(quán)限。
發(fā)給特定的用戶:
有序廣播因為要處理消息的處理結(jié)果,所以要復(fù)雜一些。
如果只是想讓廣播可以按優(yōu)先級來收取,并不在意處理的結(jié)果,可以用下面的版本:
同樣,在多用戶環(huán)境下,也可以選擇給哪個用戶發(fā)廣播:
不管是普通的還是有序的廣播都對應(yīng)有粘性的版本:
以上的API都是定義于Context類中:
首先我們先看看發(fā)送端是如何發(fā)送的。
我們首先先放一個大圖,讓大家先有一個直觀的印象,不管普通廣播、有序廣播、粘性廣播如何組合,最終都匯集到一個大方法中。
我們先看應(yīng)用發(fā)送普通廣播的一個簡單的例子:
非常簡單,調(diào)用ContentWrapper的sendBroadcast方法就可以了。
然后我們順藤摸瓜就好了。
Activity中的sendBroadcast,實際上調(diào)用的是:
我們來看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去調(diào)用AMS的broadcastIntent。由于我們這個普通的廣播的方法參數(shù)最少,所以好多都是傳null。
加鎖,定參數(shù),然后調(diào)用真正的邏輯的實現(xiàn)。
我們先把broadcastIntentLocked的真正邏輯放一下,先看看有序廣播是如何發(fā)送的。
ContextWrapper.sendOrderedBroadcast
Context是abstract方法,調(diào)用的是ContextWrapper的實現(xiàn):
跟普通廣播一樣,還是會調(diào)用到ContextImpl.sendOrderedBroadcast
有序廣播調(diào)用broadcastIntent的區(qū)別在于serialized參數(shù),普通廣播為false,有序廣播為true.
原型為:
前面講過帶有回調(diào)的版本,我們看看它是如何實現(xiàn)的:
當然還是調(diào)用ContextImpl.sendOrderedBroadcast
這次變成只是一個封裝了,它會調(diào)用一個更多參數(shù)的版本:
這次是一個全參數(shù)調(diào)用broadcastIntent的版本了,除了sticky就齊了
我們也不繞圈子了,直接看ContextImpl.sendStickyBroadcast.
以下廣播簡稱Broadcast
?? 是Android四大組件之一,在四大組件的另外兩個組件 和 擁有發(fā)送和接收廣播的能力。Android 是在 進程間通信機制的基礎(chǔ)上實現(xiàn)的,內(nèi)部基于消息發(fā)布和訂閱的事件驅(qū)動模型,廣播發(fā)送者負責發(fā)送消息,廣播接收者需要先訂閱消息,然后才能收到消息。 進程間通信與 的區(qū)別在于:
?? 有三種類型
?? 存在一個注冊中心,也可以說是一個調(diào)度中心,即 。廣播接收者將自己注冊到 中,并指定要接收的廣播類型;廣播發(fā)送者發(fā)送廣播時,發(fā)送的廣播首先會發(fā)送到 , 根據(jù)廣播的類型找到對應(yīng)的 ,找到后邊將廣播發(fā)送給其處理。
?? 這里以普通廣播為例子, 接收者有兩種注冊方式,一種是 ,一種是 :
(廣播的發(fā)送分為 兩種,這里針對有序的廣播) 中的android:priority=""和 中的IntentFilter.setPriority(int)可以用來設(shè)置廣播接收者的優(yōu)先級,默認都是0 , 范圍是[-1000, 1000],值越大優(yōu)先級越高,優(yōu)先級越高越早收到。
?? 在相同優(yōu)先級接收同個類型廣播時, 的廣播接收器比 的廣播接收者更快的接收到對應(yīng)的廣播,這個之后會進行分析。
?? 注:以下源碼基于rk3399_industry Android7.1.2
?? 的流程可分為 , 和 三個部分,這里依次分析下
?? 在Android系統(tǒng)的 機制中,前面提到, 作為一個注冊和調(diào)度中心負責注冊和轉(zhuǎn)發(fā) 。所以 的注冊過程就是把它注冊到 的過程。
?? 這里我們分析 廣播的過程, 和 有一個共同的父類 ,所以它們對應(yīng)的注冊過程其實是調(diào)用 ,接下來我們按照流程逐步分析調(diào)用流程的源碼。
frameworks/base/core/java/android/content/ContextWrapper.java
?? 在之前的 Android應(yīng)用程序啟動入口ActivityThread.main流程分析 分析過,在我們啟動 Activity 時會創(chuàng)建一個 對象,然后通過 傳給我們啟動的 ,其內(nèi)部就會將該對象賦值給 ; 的 方法也是類似的賦值流程,這里放個簡易的源碼應(yīng)該更好理解
?? 可以看到最后都會將生成的 對象賦值給對應(yīng)的
對象。接下來繼續(xù)分析 , 即 函數(shù)。
/frameworks/base/core/java/android/app/ContextImpl.java
?? 這里我們首先看下如何將廣播接收者 封裝成一個 接口的 本地對象
/frameworks/base/core/java/android/app/LoadedApk.java
?? 每一個注冊過廣播接收者的 或 組件在font color='Crimson' LoadedApk /font類中都有個對應(yīng)的 對象,該對象負責將 與 組件關(guān)聯(lián)起來。這些對象,以關(guān)聯(lián)的 作為關(guān)鍵字保存在一個 中。之后對應(yīng)的 又以 的 作為關(guān)鍵字保存在 的成員變量 對象中。最后通過 對應(yīng)的 方法獲得其 接口的 本地對象。之后再回到 注冊方法內(nèi),將 對象發(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中,而是將與它關(guān)聯(lián)的font color='OrangeRed'InnerReceiver/font對象注冊到font color='OrangeRed'AMS/font中,當font color='OrangeRed'AMS/font接收到廣播時,會根據(jù) 在內(nèi)部找到對應(yīng)的font color='OrangeRed'InnerReceiver/font對象,然后在通過這個對象將這個廣播發(fā)送給對應(yīng)的 處理。
?? 注冊過程這邊畫了一個簡單的流程圖:
?? 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
有兩種注冊廣播方式:
1.常駐型廣播
常駐型廣播,當應(yīng)用程序關(guān)閉了,如果有廣播信息來,寫的廣播接收器同樣的能接收到,它的注冊方式就是在應(yīng)用程序的AndroidManifast.xml 中進行注冊,這種注冊方式通常又被稱作靜態(tài)注冊。這種方式可以理解為通過清單文件注冊的廣播是交給操作系統(tǒng)去處理的。示例代碼如下:
AndroidManifest.xml中配置廣播
?xml version="1.0" encoding="utf-8"?
manifest xmlns:android=""
package="spl.broadCastReceiver"
android:versionCode="1"
android:versionName="1.0"
application android:icon="@drawable/icon" android:label="@string/app_name"
activity android:name=".BroadCastReceiverActivity"
android:label="@string/app_name"
intent-filter
action android:name="android.intent.action.MAIN" /
category android:name="android.intent.category.LAUNCHER" /
/intent-filter
/activity
!--廣播注冊、name里面填寫廣播類的路徑--
receiver android:name=".SmsBroadCastReceiver"
intent-filter android:priority="20"
action android:name="android.provider.Telephony.SMS_RECEIVED"/
/intent-filter
/receiver
/application
uses-sdk android:minSdkVersion="7" /
!-- 權(quán)限申請 --
uses-permission android:name="android.permission.RECEIVE_SMS"/uses-permission
/manifest
2.非常駐型廣播
非常駐型廣播,當應(yīng)用程序結(jié)束了,廣播自然就沒有了,比如在 Activity 中的 onCreate 或者 onResume 中注冊廣播接收者,在 onDestory 中注銷廣播接收者。這樣廣播接收者就一個非常駐型的了,這種注冊方式也叫動態(tài)注冊。這種方式可以理解為通過代碼注冊的廣播是和注冊者關(guān)聯(lián)在一起的。比如寫一個監(jiān)聽 SDcard 狀態(tài)的廣播接收者:
package cn.sunzn.mosecurity.activity;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Environment;
public class SDcard extends Activity {
SdcardStateChanageReceiver sdcardStateReceiver;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sdcardStateReceiver = new SdcardStateChanageReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_REMOVED);
filter.addAction(Intent.ACTION_MEDIA_EJECT);
filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
filter.addDataScheme("file");
registerReceiver(sdcardStateReceiver, filter);
}
protected void onDestroy() {
unregisterReceiver(sdcardStateReceiver);
}
class SdcardStateChanageReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
checkSDCard();
}
public void checkSDCard() {
String state = Environment.getExternalStorageState();
System.out.println(state);
if (state.equals(Environment.MEDIA_REMOVED) || state.equals(Environment.MEDIA_UNMOUNTED)) {
System.out.println("SDCard 已卸載!");
}
}
}
}
首先寫一個類要繼承BroadcastReceiver\x0d\x0a第一種:在清單文件中聲明,添加\x0d\x0a\x0d\x0a \x0d\x0a \x0d\x0a\x0d\x0a第二種使用代碼進行注冊如:\x0d\x0aIntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");\x0d\x0aIncomingSMSReceiver receiver = new IncomgSMSReceiver();\x0d\x0aregisterReceiver(receiver.filter);
網(wǎng)站標題:android注冊廣播,android注冊廣播的方式
分享地址:http://chinadenli.net/article4/dsgojoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、定制網(wǎng)站、商城網(wǎng)站、Google、域名注冊、網(wǎng)站導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)