Android四大組件之BroadcastReceiver

Android四大組件之Activity
Android四大組件之Service
Android四大組件之BroadcastReceiver
Android四大組件之ContentProvider

BroadcastReceiver作為Android四大組件之一,即廣播。廣播分為發(fā)送者和接收者。要想使用廣播,首先必須先注冊(cè)廣播接收者,然后接著發(fā)送廣播。最后在接收者中處理廣播。

1.廣播接收者BroadcastReceiver的使用

1.1創(chuàng)建BroadcastReceiver

繼承BroadcastReceivre基類(lèi),必須復(fù)寫(xiě)抽象方法onReceive()方法。
代碼如下:

public class MyReceivre  extends BroadcastReceiver{

    // 復(fù)寫(xiě)onReceive()方法,接收到廣播后,則自動(dòng)調(diào)用該方法
    @Override
    public void onReceive(Context context, Intent intent) {
        //寫(xiě)入接收廣播后的操作
    }
}

1.2注冊(cè)BroadcastReceiver

注冊(cè)的方式分為兩種:靜態(tài)注冊(cè)、動(dòng)態(tài)注冊(cè)

1.2.1靜態(tài)注冊(cè)

一般為常駐廣播,在AndroidManifest.xml里通過(guò)<receive>標(biāo)簽聲明

 <receiver android:name=".MyReceivre">
      <intent-filter>
           <!--屏幕被打開(kāi)之后的廣播-->
           <action android:name="android.intent.action.ACTION_SCREEN_ON"/>
      </intent-filter>
</receiver>

當(dāng)此 App首次啟動(dòng)時(shí),系統(tǒng)會(huì)自動(dòng)實(shí)例化MyReceivre 類(lèi),并注冊(cè)到系統(tǒng)中。

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

非常駐廣播,在使用時(shí)注冊(cè),用完及時(shí)銷(xiāo)毀。在代碼中動(dòng)態(tài)注冊(cè)示例如下:

public class MainActivity extends AppCompatActivity {

    private MyReceivre mMyReceivre;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //1.實(shí)例化BroadcastReceiver子類(lèi) &  IntentFilter
        mMyReceivre = new MyReceivre();
        IntentFilter intentFilter = new IntentFilter();
        //2.設(shè)置接收廣播的類(lèi)型
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        //3.動(dòng)態(tài)注冊(cè):調(diào)用Context的registerReceiver()方法
        registerReceiver(mMyReceivre, intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //銷(xiāo)毀在onDestroy()方法中的廣播
        unregisterReceiver(mMyReceivre);
    }
}

需要注意:
對(duì)于動(dòng)態(tài)廣播,有注冊(cè)就必然得有注銷(xiāo),否則會(huì)導(dǎo)致內(nèi)存泄露,重復(fù)注冊(cè)、重復(fù)注銷(xiāo)也不允許。

2.廣播發(fā)送者

2.1廣播的發(fā)送

廣播發(fā)送者 將此廣播的“意圖(Intent)”通過(guò)sendBroadcast()方法發(fā)送出去。

2.2 廣播的類(lèi)型

廣播的類(lèi)型主要分為5類(lèi):

  • 普通廣播(Normal Broadcast)
  • 系統(tǒng)廣播(System Broadcast)
  • 有序廣播(Ordered Broadcast)
  • 粘性廣播(Sticky Broadcast)
  • 本地廣播(Local Broadcast)
2.2.1普通廣播

開(kāi)發(fā)者自身定義 intent的廣播,通過(guò)Context.sendBroadcast(Intent intent)發(fā)送,可以同時(shí)被所有廣播接收者無(wú)需等待的接收到。
優(yōu)點(diǎn):消息傳遞的效率比較高。
缺點(diǎn):
1、接收者不能修改該廣播。
2、無(wú)法終止廣播Intent的傳播,即無(wú)法阻止其他接收者的接收動(dòng)作。

Intent intent = new Intent();
//對(duì)應(yīng)BroadcastReceiver中intentFilter的action
intent.setAction("ACTION"); 
//發(fā)送的內(nèi)容
intent.putExtra("msg", "這是一條普通廣播");
//發(fā)送廣播
sendBroadcast(intent);
2.2.2系統(tǒng)廣播

只要涉及到手機(jī)的基本操作(如開(kāi)機(jī)、網(wǎng)絡(luò)狀態(tài)變化、拍照等等),基本上都會(huì)發(fā)出相應(yīng)的系統(tǒng)廣播。每個(gè)系統(tǒng)廣播都具有特定的intent-filter,其中主要包括具體的action,系統(tǒng)廣播發(fā)出后,將被相應(yīng)的BroadcastReceiver接收。系統(tǒng)廣播在系統(tǒng)內(nèi)部當(dāng)特定事件發(fā)生時(shí),由系統(tǒng)自動(dòng)發(fā)出。當(dāng)使用系統(tǒng)廣播時(shí),只需要在注冊(cè)廣播接收者時(shí)定義相關(guān)的action即可,并不需要手動(dòng)發(fā)送廣播,當(dāng)系統(tǒng)有相關(guān)操作時(shí)會(huì)自動(dòng)進(jìn)行系統(tǒng)廣播。系統(tǒng)廣播常量見(jiàn)文末。

2.2.3有序廣播

通過(guò)Context.sendOrderedBroadcast(intent, receiverPermission)發(fā)送,是按照接收者聲明的優(yōu)先級(jí)別,被接收者依次接收廣播。

廣播接受者接收廣播的順序規(guī)則(同時(shí)面向靜態(tài)和動(dòng)態(tài)注冊(cè)的廣播接受者)
1、按照Priority屬性值從大-小排序;
2、Priority屬性相同者,動(dòng)態(tài)注冊(cè)的廣播優(yōu)先。

優(yōu)點(diǎn):
1、廣播可以通過(guò)接收者調(diào)用abortBroadcast()方法截?cái)鄰V播(被截?cái)嗟膹V播不能再繼續(xù)傳遞該廣播)。
2、接收者能修改處理結(jié)果(比如通過(guò)傳遞Bundle)傳遞給下一個(gè)接收者(一般情況下,不建議對(duì)有序廣播進(jìn)行此類(lèi)操作,尤其是針對(duì)系統(tǒng)中的有序廣播)。
缺點(diǎn):消息傳遞的效率比普通廣播低。

Intent intent2 = new Intent();
intent2.setAction("ACTION");
intent2.putExtra("msg", "這是一條有序廣播");
sendOrderedBroadcast(intent2, null);
2.2.4粘性廣播

通過(guò)mContext.sendStickyBroadcast(intent)發(fā)送,此廣播會(huì)一直滯留(等待),以便有人注冊(cè)這則廣播消息后能盡快的收到這條廣播。其他功能與sendBroadcast相同。但是使用sendStickyBroadcast 發(fā)送廣播需要獲得BROADCAST_STICKY permission,如果沒(méi)有這個(gè)permission則會(huì)拋出異常。在Android5.0 & API 21中已經(jīng)失效。

2.2.5本地廣播

本地廣播和其他的廣播有些不同,它是使用LocalBroadcastManager來(lái)發(fā)送廣播以及注冊(cè)廣播接收器的。
優(yōu)點(diǎn):它發(fā)出的廣播只會(huì)在應(yīng)用程序的內(nèi)部傳播,不用擔(dān)心廣播被其他應(yīng)用接收,造成數(shù)據(jù)泄漏,而廣播接收器也只能接收到自己應(yīng)用發(fā)出的廣播,不會(huì)接收別的應(yīng)用發(fā)來(lái)的廣播,防止接收垃圾信息。
和其他廣播用法有點(diǎn)區(qū)別,具體是使用LocalBroadcastManager類(lèi),示例如下:

//發(fā)送應(yīng)用內(nèi)廣播
Intent intent = new Intent();
intent.setAction("action");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);


//注冊(cè)應(yīng)用內(nèi)廣播接收器
//1.實(shí)例化LocalBroadcastManager的實(shí)例
LocalBroadcastManager mBroadcastManager = LocalBroadcastManager.getInstance(this);
IntentFilter intentFilter = new IntentFilter();
//2.設(shè)置接收廣播的類(lèi)型
intentFilter.addAction("action");
//3.接收由發(fā)送廣播的界面?zhèn)鱽?lái)的值(沒(méi)有傳值不用寫(xiě))
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        //接收由發(fā)送廣播的界面?zhèn)鱽?lái)的值(沒(méi)有傳值不用寫(xiě))
    }
};
//4.調(diào)用LocalBroadcastManager單一實(shí)例的registerReceiver()方法進(jìn)行動(dòng)態(tài)注冊(cè)
mBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);


//5.取消注冊(cè)應(yīng)用內(nèi)廣播接收器(一定要取消注冊(cè))
mBroadcastManager.unregisterReceiver(mBroadcastReceiver);

注:對(duì)于LocalBroadcastManager方式發(fā)送的應(yīng)用內(nèi)廣播,只能通過(guò)LocalBroadcastManager動(dòng)態(tài)注冊(cè),不能靜態(tài)注冊(cè)
LocalBroadcastManager源碼學(xué)習(xí)

    private static LocalBroadcastManager mInstance;

    @NonNull
    public static LocalBroadcastManager getInstance(@NonNull Context context) {
        synchronized (mLock) {
            if (mInstance == null) {
                mInstance = new LocalBroadcastManager(context.getApplicationContext());
            }
            return mInstance;
        }
    }

    private LocalBroadcastManager(Context context) {
        mAppContext = context;
        //在主線程中操作
        mHandler = new Handler(context.getMainLooper()) {

            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_EXEC_PENDING_BROADCASTS:
                        executePendingBroadcasts();
                        break;
                    default:
                        super.handleMessage(msg);
                }
            }
        };
    }
  • 在獲取LocalBroadcastManager對(duì)象實(shí)例的時(shí)候,這里用了單例模式。并且把外部傳進(jìn)來(lái)的Context 轉(zhuǎn)化成了ApplicationContext,有效的避免了當(dāng)前Context的內(nèi)存泄漏的問(wèn)題。這一點(diǎn)我們?cè)谠O(shè)計(jì)單例模式框架的時(shí)候是值得學(xué)習(xí)的,看源碼可以學(xué)習(xí)到很多東西。
  • 在LocalBroadcastManager構(gòu)造函數(shù)中創(chuàng)建了一個(gè)Handler.可見(jiàn) LocalBroadcastManager 的本質(zhì)上是通過(guò)Handler機(jī)制發(fā)送和接收消息的。
  • 在創(chuàng)建Handler的時(shí)候,用了 context.getMainLooper() , 說(shuō)明這個(gè)Handler是在Android 主線程中創(chuàng)建的,廣播接收器的接收消息的時(shí)候會(huì)在Android 主線程,所以我們決不能在廣播接收器里面做耗時(shí)操作,以免阻塞UI。

附:部分系統(tǒng)廣播常量

系統(tǒng)操作 action
監(jiān)聽(tīng)網(wǎng)絡(luò)變化 android.net.conn.CONNECTIVITY_CHANGE
屏幕被關(guān)閉 Intent.ACTION_SCREEN_OFF
屏幕被打開(kāi) Intent.ACTION_SCREEN_ON
屏幕鎖屏 Intent.ACTION_CLOSE_SYSTEM_DIALOGS
關(guān)閉或打開(kāi)飛行模式 Intent.ACTION_AIRPLANE_MODE_CHANGED
充電時(shí)或電量發(fā)生變化 Intent.ACTION_BATTERY_CHANGED
電池電量低 Intent.ACTION_BATTERY_LOW
電池電量充足 Intent.ACTION_BATTERY_OKAY
插上外部電源時(shí)發(fā)出的廣播 Intent.ACTION_POWER_CONNECTED
已斷開(kāi)外部電源連接時(shí)發(fā)出的廣播 Intent.ACTION_POWER_DISCONNECTED
關(guān)閉或打開(kāi)飛行模式 Intent.ACTION_AIRPLANE_MODE_CHANGED
系統(tǒng)啟動(dòng)完成后 Intent.ACTION_BOOT_COMPLETED
按下照相時(shí)的拍照按鍵(硬件按鍵)時(shí) Intent.ACTION_CAMERA_BUTTON
插入耳機(jī)時(shí) Intent.ACTION_HEADSET_PLUG
成功安裝APK Intent.ACTION_PACKAGE_ADDED
成功刪除APK Intent.ACTION_PACKAGE_REMOVED
重啟設(shè)備 Intent.ACTION_REBOOT
關(guān)閉系統(tǒng)時(shí) Intent.ACTION_SHUTDOWN
改變輸入法時(shí)發(fā)出的廣播 Intent.ACTION_INPUT_METHOD_CHANGED
設(shè)備當(dāng)前區(qū)域設(shè)置已更改時(shí)發(fā)出的廣播 Intent.ACTION_LOCALE_CHANGED
時(shí)間被設(shè)置時(shí)發(fā)出的廣播 Intent.ACTION_TIME_CHANGED
時(shí)區(qū)發(fā)生改變時(shí)發(fā)出的廣播 Intent.ACTION_TIMEZONE_CHANGED
設(shè)備日期發(fā)生改變時(shí)會(huì)發(fā)出此廣播 Intent.ACTION_DATE_CHANGED

關(guān)于廣播就學(xué)習(xí)到這里,如理解有誤,還望指正,謝謝!

最后編輯于
?著作權(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),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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