BoradcastReceiver的學習

這是之前保存的學習筆記, 現在上傳保存一下

BoradcastReceiver的使用

BroadcastReceiver翻譯爲廣播接收者,Broadcast是一種廣泛運用在應用程序之間的傳輸信息的機制,簡單的可以理解爲傳統意義上的電臺廣播,通俗一點,發佈失物招領。

廣播機制是一個典型的發佈—訂閱模式,也就是我們所說的觀察者模式。廣播最大的特點就是發送方並不關心接收方是否接到數據,也不關心接收方是如何處理數據的,通過這樣的形式來達到接、收雙方的完全解耦合

1,普通廣播

普通廣播是完全異步的,通過Context的sendBroadcast()方法來發送,消息傳遞效率比較高,但所有receivers(接收器)的執行順序不確定。

缺點是:接收者不能將處理結果傳遞給下一個接收者,並且無法終止廣播Intent的傳播,直到沒有與之匹配的廣播接收器爲止。

自定義廣播

1,創建廣播

繼承BroadcastReceiver並實現onReceive()方法

public class SendMyBroadCast extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

    }
}

2,註冊廣播

BroadcastReceiver是四大組件之一,所以必須要註冊,其註冊方法有兩種:

1,在 androidmanifests 中進行配置

<receiver android:name=".broadcast.SendMyBroadCast" >
     <intent-filter>
         <action android:name="con.neishenme.sendmyself" />
     </intent-filter>
</receiver>

這裏需要加入intent-filter的action中的name屬性,表示我們監聽的內容。當有廣播發送時,需要判斷該廣播是否和我們監聽的內容一致,如果一致則接收.

2,通過代碼動態配置

SendMyBroadCast sendMyBroadCast = new SendMyBroadCast();
IntentFilter filter = new IntentFilter("con.neishenme.sendmyself");
registerReceiver(sendMyBroadCast, filter);

3,取消廣播註冊

BroadcastReceiver必須遵循生到死的週期,如果你是使用動態註冊廣播的則需要在Activity的onDestroy的時候取消註冊; 如果是靜態註冊(在manifests中註冊)則不需要取消註冊.

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

4,發送廣播

Intent intent = new Intent("con.neishenme.sendmyself");
sendBroadcast(intent);

2,有序廣播

有序廣播通過Context.sendOrderedBroadcast()來發送,所有的廣播接收器優先級依次執行,廣播接收器的優先級通過receiver的intent-filter中的android:priority屬性來設置,數值越大優先級越高。

當廣播接收器接收到廣播後,可以使用setResult()函數來結果傳給下一個廣播接收器接收,然後通過getResult()函數來取得上個廣播接收器接收返回的結果。

當廣播接收器接收到廣播後,也可以用abortBroadcast()函數來讓系統攔截下來該廣播,並將該廣播丟棄,使該廣播不再傳送到別的廣播接收器接收

有序廣播的過程

1,創建廣播

public class SendOrderMyBroadCast {
    public static class HignPriority extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i("hehe", "高權限獲接收到了廣播");

            int resultCode = getResultCode();
            Log.i("hehe", "高權限code爲: " + resultCode);
            String resultData = getResultData();
            Log.i("hehe", "高權限resultData爲: " + resultData);
            Bundle resultExtras = getResultExtras(true);
            Log.i("hehe", "高權限resultExtras爲: " + resultExtras);

            int code = 10;
            String data = "hellohigh";
            setResult(code, data, null);
        }
    }

    public static class MidPriority extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i("hehe", "中等權限獲接收到了廣播");

            int resultCode = getResultCode();
            Log.i("hehe", "中等權限code爲: " + resultCode);
            String resultData = getResultData();
            Log.i("hehe", "中等權限resultData爲: " + resultData);
            Bundle resultExtras = getResultExtras(true);
            Log.i("hehe", "中等權限resultExtras爲: " + resultExtras);

            int code = 100;
            String data = "hellomid";
            setResult(code, data, null);
        }
    }

    public static class LowPriority extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i("hehe", "低權限獲接收到了廣播");

            int resultCode = getResultCode();
            Log.i("hehe", "低權限code爲: " + resultCode);
            String resultData = getResultData();
            Log.i("hehe", "低權限resultData爲: " + resultData);
            Bundle resultExtras = getResultExtras(true);
            Log.i("hehe", "低權限resultExtras爲: " + resultExtras);
        }
    }
}

要注意的是:內部類的BroadcastReceiver必須由public static修飾,否則會報錯

2,註冊廣播

這裏的註冊方式和普通廣播是一樣的,這裏的區別在於priority屬性,確定了他們之間的優先級
這裏也可以通過代碼註冊, 但是需要通過設置優先級

<receiver android:name=".broadcast.SendOrderMyBroadCast$HignPriority">
    <intent-filter android:priority="1000">
        <action android:name="con.neishenme.sendmyself" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.SendOrderMyBroadCast$MidPriority">
    <intent-filter android:priority="500">
        <action android:name="con.neishenme.sendmyself" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.SendOrderMyBroadCast$LowPriority">
    <intent-filter android:priority="100">
        <action android:name="con.neishenme.sendmyself" />
    </intent-filter>
</receiver>

3,發送廣播

和之前的不一樣的地方,這裏是使用sendOrderedBroadcast()發送有序廣播

public void send(View view) {
    Intent intent = new Intent("con.neishenme.sendmyself");
    sendOrderedBroadcast(intent, null);
}

結果爲:

02-27 14:38:56.103 22772-22772/com.demo.downrefresh I/hehe: 高權限獲接收到了廣播
02-27 14:38:56.103 22772-22772/com.demo.downrefresh I/hehe: 高權限code爲: -1
02-27 14:38:56.103 22772-22772/com.demo.downrefresh I/hehe: 高權限resultData爲: null
02-27 14:38:56.108 22772-22772/com.demo.downrefresh I/hehe: 中等權限獲接收到了廣播
02-27 14:38:56.108 22772-22772/com.demo.downrefresh I/hehe: 中等權限code爲: 10
02-27 14:38:56.108 22772-22772/com.demo.downrefresh I/hehe: 中等權限resultData爲: hellohigh
02-27 14:38:56.111 22772-22772/com.demo.downrefresh I/hehe: 低權限獲接收到了廣播
02-27 14:38:56.111 22772-22772/com.demo.downrefresh I/hehe: 低權限code爲: 100
02-27 14:38:56.111 22772-22772/com.demo.downrefresh I/hehe: 低權限resultData爲: hellomid

要注意的是:

這裏需要發送的是有序廣播,否則在接收者中通過setResult()和getResult()方法會取不到值,因爲只有有序廣播才能傳遞結果

3,攔截廣播

通過在BroadcastReceiver中,執行abortBroadcast()方法,廣播就不會繼續往下傳遞了

在 onRecive 中調用該方法

public static class HignPriority extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("hehe", "高權限獲接收到了廣播");

        int resultCode = getResultCode();
        Log.i("hehe", "高權限code爲: " + resultCode);
        String resultData = getResultData();
        Log.i("hehe", "高權限resultData爲: " + resultData);

        int code = 10;
        String data = "hellohigh";
        setResult(code, data, null);

        //攔截廣播
        abortBroadcast();
    }
}

終結廣播

現在有這樣的一個應用場景,按照上面的程序走,只能在第一個廣播中被攔截住了,後面的廣播則不執行。如果這個時候我們需要一個不管有沒有被攔截都必須執行的廣播,我們稱爲終結廣播,那應該怎麼辦。

同樣的,發送有序廣播也考慮到這一點,通過以下代碼來發送廣播,並指定我們不管有沒有被攔截都必須執行的終結廣播

Intent intent = new Intent("con.neishenme.sendmyself");
//sendOrderedBroadcast(intent, null);
sendOrderedBroadcast(intent, null, new SendOrderMyBroadCast.LowPriority(), new Handler(), 0, "hehe", null);

可以發現,之前只是有High的Log信息,因爲是被攔截了,而Log信息多了一條Low,說明我們攔截後,還要執行終結廣播。

有兩點需要注意

1,終結廣播是肯定能獲取到的,但是其獲取getResultCode和getResultDate的時候是攔截的時候的值,abortBroadcast() 方法不分調用的順序,在setResult之前和之後調用的情況是一樣的. PS: sendOrderedBroadcast有兩個重載的方法 , 第二個方法代表 肯定可以執行到的廣播 和 code,data和bundle的初始值 , 在第一個攔截後其設置的值 即爲修改之後的值

2,在有序廣播中,廣播接受者必須是一個一個的收到廣播的, 兩個廣播的priority值相同,那麼接收廣播的順序是按照 在 manifest 聲明順序 或者 代碼註冊的時候 的註冊順序來決定的, 所以兩個同樣爲 500的優先級的先註冊的broadcast 可以通過 abortBroadcast() 方法來讓後註冊接收者 獲取不到,即比較方法有兩種, 先是通過 priority 的優先值 ,其次 priority相同通過註冊的先後順序來 比較 .

4,本地廣播

在API21的Support v4包中新增本地廣播,也就是LocalBroadcastManager。

由於之前的廣播都是全局的,所有應用程序都可以接收到,這樣就會帶來安全隱患,所以我們使用LocalBroadcastManager只發送給自己應用內的信息廣播,限制在進程內使用。

它的用法很簡單,只需要把調用context的sendBroadcast、registerReceiver、unregisterReceiver的地方換爲LocalBroadcastManager.getInstance(Context context)中對應的函數即可。

其大致流程是一樣的:

//1,獲取本地廣播的管理器
LocalBroadcastManager instance = LocalBroadcastManager.getInstance(this);
//2,動態註冊廣播
instance.registerReceiver(sendMyBroadCast, filter);
//3,發送廣播
instance.sendBroadcast(intent);

有兩點需要注意

1,本地廣播的方法並不多, 主要有: registerReceiver(註冊廣播) , unregisterReceiver(取消註冊廣播) , sendBroadcast(發送異步廣播) , sendBroadcastSync(發送同步廣播)四個方法

2,本地廣播只支持代碼中註冊的廣播, 在manifest中聲明的廣播是接收不到廣播的 !

5,Sticky廣播 (粘性廣播, 即可以短時間滯留)(API 21過時了)

sticky廣播通過Context.sendStickyBroadcast()函數來發送,用此函數發送的廣播會一直滯留,當有匹配此廣播的廣播接收器被註冊後,該廣播接收器就會收到此條信息。(已經過時了)

使用此函數需要發送廣播時,需要獲得BROADCAST_STICKY權限

<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

sendStickyBroadcast只保留最後一條廣播,並且一直保留下去,這樣即使已經有廣播接收器處理了該廣播,當再有匹配的廣播接收器被註冊時,此廣播仍會被接收。如果你只想處理一遍該廣播,可以通過removeStickyBroadcast()函數來實現。

ps:目前由於一些安全問題,系統已經不建議使用 Sticky broadcasts。

6,系統廣播

系統中也會有很多自帶的廣播,當符合一定條件時,系統會發送一些定義好的廣播,比如:重啓、充電、來電電話等等。我們可以通過action屬性來監聽我們的系統廣播

常用的廣播action屬性有

屏幕被關閉之後的廣播:Intent.ACTION_SCREEN_OFF(只能通過代碼註冊)
屏幕被打開之後的廣播:Intent.ACTION_SCREEN_ON(只能通過代碼註冊)
充電狀態,或者電池的電量發生變化:Intent.ACTION_BATTERY_CHANGED(只能通過代碼註冊)
關閉或打開飛行模式時的廣播:Intent.ACTION_AIRPLANE_MODE_CHANGED(可靜態)
表示電池電量低:Intent.ACTION_BATTERY_LOW(可以靜態註冊)
表示電池電量充足,即電池電量飽滿時會發出廣播:Intent.ACTION_BATTERY_OKAY(可靜態)
按下照相時的拍照按鍵(硬件按鍵)時發出的廣播:Intent.ACTION_CAMERA_BUTTON(可靜態)
時間變化的廣播: Intent.ACTION_TIME_CHANGED(只能通過代碼註冊)
時間變化廣播:  ACTION_TIME_CHANGED(時間被設置),ACTION_DATE_CHANGED(日期變化)(這兩個可靜態)
            ACTION_TIME_TICK(分鐘變化,這個需要通過代碼動態註冊)
開機廣播: ACTION_BOOT_COMPLETED
安裝app:ACTION_PACKAGE_INSTALL ,安裝app完成;ACTION_PACKAGE_ADDED
位置變化: ACTION_LOCALE_CHANGED
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章