天天看點

Android 元件BroadcastReceiver詳解

1.什麼是BroadcastReceiver?

是一個全局的監聽器,屬于Android四大元件之一,主要監聽 或者 接收 應用 App 發出的廣播消息,并 做出響應。

Android不同元件間的通信,多線程通信,與 Android 系統在特定情況下的通信等等都能用到廣播。

Android中的廣播采用了觀察者模式的設計模式去實作:基于消息的釋出 / 訂閱事件模型。

2.廣播不同角度各種分類

  • 按照注冊方式劃分
可分為靜态廣播注冊和動态廣播注冊
  • 按照廣播發送順序
有序廣播、普通廣播
  • 按照廣播範圍
本地廣播、系統廣播

3.靜态廣播注冊和靜态廣播注冊

  • 靜态廣播注冊

    1)建立class內建Broadcastreceiver并重寫相關方法

public class BroardCastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e("TAG","============"+intent.getStringExtra("name"));
    }
}
           

2)AndroidManifest.xml清單檔案中注冊廣播

<receiver android:name=".BroardCastReceiver">
            <intent-filter>
                <action android:name="com.org.mybroadcastreceiver"></action>
            </intent-filter>
        </receiver>
           

3)發送廣播

Intent intent=new Intent();
        intent.setAction("com.org.mybroadcastreceiver");
        intent.putExtra("name","我是通過靜态注冊的普通廣播");
        sendBroadcast(intent);
           
  • 動态廣播注冊

    1).定義自定義廣播重寫相應的方法

    2)代碼動态注冊代碼

    3)解注冊

    4)調用

public class MainActivity extends AppCompatActivity {
    MyDynamicBroadCastReceiver myDynamicBroadCastReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        registerBroadCastReceiver();

    }

    /**
     * 2)注冊廣播
     */
    private void registerBroadCastReceiver() {
         myDynamicBroadCastReceiver = new MyDynamicBroadCastReceiver();
        IntentFilter intent=new IntentFilter();
        intent.addAction("com.org.mydynamicbroadcastreceiver");
        registerReceiver(new MyDynamicBroadCastReceiver(),intent);
    }

    public void sendBroadCastReceiverStatic(View view){
        Intent intent=new Intent();
        intent.setAction("com.org.mybroadcastreceiver");
        intent.putExtra("name","我是通過靜态注冊的普通廣播");
        sendBroadcast(intent);
    }

    /**
     * 4)發送廣播
     * @param view
     */
    public void sendBroadCastReceiverDynamic(View view){
        Intent intent=new Intent();
        intent.setAction("com.org.mydynamicbroadcastreceiver");
        intent.putExtra("name","我是通過動态注冊的普通廣播");
        sendBroadcast(intent);
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        //3)解注冊廣播釋放資源
        unregisterReceiver(myDynamicBroadCastReceiver);
    }

    /**
     * 1)自定義廣播類
     */
    class MyDynamicBroadCastReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("TAG", "==============="+intent.getStringExtra("name"));
        }
    }


}
           

注意

動态注冊的廣播接收器可以自由地控制注冊與登出,在靈活性方面有很大的優勢,但是它也存在着一個缺點,即必須要在程式啟動之後才能接收到廣播,因為注冊的邏輯是寫在onCreate()方法中的。那麼有沒有什麼辦法可以讓程式在未啟動的情況下就能接收到廣播呢?這就需要使用靜态注冊的方式了

不能靜态注冊的廣播:

android.intent.action.SCREEN_ON  //螢幕被打開之後的廣播

  android.intent.action.SCREEN_OFF  螢幕被關閉之後的廣播

  android.intent.action.BATTERY_CHANGED   充電狀态,或者電池的電量發生變化

  android.intent.action.CONFIGURATION_CHANGED  

  android.intent.action.TIME_TICK
           

3.有序廣播

BroadcastReceiver可以使用setResult系列函數來結果傳給下一個BroadcastReceiver,通過getResult系列函數來取得上個BroadcastReceiver傳回的結果,并可以abortBroadcast()函數來讓系統丢棄該廣播,使用該廣播不再傳送到别的BroadcastReceiver。

可以通過在intent-filter中設定android:priority屬性來設定receiver的優先級,優先級相同的receiver其執行順序不确定。

如果BroadcastReceiver是代碼中注冊的話,且其intent-filter擁有相同android:priority屬性的話,先注冊的将先收到廣播

有序廣播,即從優先級别最高的廣播接收器開始接收,接收完了如果沒有丢棄,就下傳給下一個次高優先級别的廣播接收器進行處理。

1) 定義3個廣播分别去接收同一發送者發送的廣播。

public class PriorityBroadcastReceiver  {
    public static class HighPriority extends BroadcastReceiver {
        //進階廣播接收者
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("TAG", "優先級高的");
            //傳遞結果到下一個廣播接收器
            int code = ;
            String data = "我是有序廣播";
            Bundle bundle = null;
            setResult(code, data, bundle);

        }
    }

    public static class MidPriority extends BroadcastReceiver {
        //中級廣播接收者
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("TAG", "優先級中等");
            //擷取上一個廣播接收器結果s
            int code = getResultCode();
            String data = getResultData();
            Log.e("TAG", "擷取到上一個廣播接收器結果:" + "code=" + code + "data=" + data);
            //終止廣播傳遞
            abortBroadcast();
        }
    }

    public static class LowPriority extends BroadcastReceiver {
        //低級廣播接收者
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("TAG", "優先級低的");
            int code = getResultCode();
            String data = getResultData();
            Log.e("TAG", "擷取到上一個廣播接收器結果:" + "code=" + code + "data=" + data);
        }
    }

}
           

2)廣播清單檔案中注冊

裡面的android:priority=”100”就是設定廣播接收器的級别,這個值從1000~-1000,數值越大,優先級别就越高

<receiver android:name=".PriorityBroadcastReceiver$HighPriority">
            <intent-filter
                android:priority="999"
                >
                <action android:name="com.org.mysortbroadcastreceiver"></action>
            </intent-filter>
        </receiver>

        <receiver android:name=".PriorityBroadcastReceiver$MidPriority">
            <intent-filter
                android:priority="888"
                >
                <action android:name="com.org.mysortbroadcastreceiver"></action>
            </intent-filter>
        </receiver>

        <receiver android:name=".PriorityBroadcastReceiver$LowPriority">
            <intent-filter
                android:priority="777"
                >
                <action android:name="com.org.mysortbroadcastreceiver"></action>
            </intent-filter>
        </receiver>
           

3)發送有序廣播

Intent intent=new Intent();
        intent.setAction("com.org.mysortbroadcastreceiver");
        intent.putExtra("name","我是有序廣播");
        sendOrderedBroadcast(intent,null);
           

輸出log

- :: -/com.phone.test_broadcastreceiver E/TAG: 優先級高的
- :: -/com.phone.test_broadcastreceiver E/TAG: 優先級中等
- :: -/com.phone.test_broadcastreceiver E/TAG: 擷取到上一個廣播接收器結果:code=data=我是有序廣播
           

如果在MidPriority攔截的廣播,但是還想在Low中接收到廣播還可以這樣做

Intent intent=new Intent();
        intent.setAction("com.org.mysortbroadcastreceiver");
        intent.putExtra("name","我是有序廣播");
        sendOrderedBroadcast(intent,null,new PriorityBroadcastReceiver.LowPriority(),new Handler(),,null,null);
           

log如下:

- :: -/com.phone.test_broadcastreceiver E/TAG: 優先級高的
- :: -/com.phone.test_broadcastreceiver E/TAG: 優先級中等
- :: -/com.phone.test_broadcastreceiver E/TAG: 擷取到上一個廣播接收器結果:code=data=我是有序廣播
- :: -/com.phone.test_broadcastreceiver E/TAG: 優先級低的
- :: -/com.phone.test_broadcastreceiver E/TAG: 擷取到上一個廣播接收器結果:code=data=我是有序廣播
           

4.本地廣播

發出的廣播隻能夠在應用程式的内部進行傳遞,并且廣播接收器也隻能接收來自本應用程式發出的廣播。

  • 可以明确地知道正在發送的廣播不會離開本程式,是以不需要擔心機密資料洩漏的問題。
  • 其他程式無法将廣播發送到本程式的内部,是以不需要擔心會有安全漏洞的隐患。
  • 發送本地廣播比起發送系統全局廣播将會更加高效

注冊本地廣播

/**
     * 注冊廣播
     */
    private void registerReceiverLocal() {
        localBroadcastManager = LocalBroadcastManager.getInstance(this);

        IntentFilter filter=new IntentFilter();
        filter.addAction("com.org.localreceiver");
        localBroadcastManager.registerReceiver(myDynamicBroadCastReceiver,filter);
    }
           

發送廣播

/**
     * 發送本地廣播
     */
    public void sendLocalReceiver(){

        Intent intent=new Intent();
        intent.setAction("com.org.localreceiver");
        localBroadcastManager.sendBroadcast(intent);
    }
           

解注冊

//在生命周期最後釋放資源
 localBroadcastManager.unregisterReceiver(myDynamicBroadCastReceiver);
           

**

注意本地廣播不能是用靜态注冊的方式去注冊

**

5.在使用廣播的特殊注意

  • 廣播中啟動activity
//需要開啟新的任務棧去存放要啟動的activity,否則會報錯
Intent intent1=newIntent(context,main.class);
intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent1);
           
  • 廣播中打開對話框

6.常見的系統廣播

action 含義
android.net.conn.CONNECTIVITY_CHANGE 監聽網絡變化
Intent.ACTION_AIRPLANE_MODE_CHANGED 關閉或打開飛行模式
Intent.ACTION_BATTERY_CHANGED 充電時或電量發生變化
Intent.ACTION_BATTERY_LOW 電池電量低
Intent.ACTION_BATTERY_OKAY 電池電量充足(即從電量低變化到飽滿時會發出廣播
Intent.ACTION_BOOT_COMPLETED 系統啟動完成後(僅廣播一次)
Intent.ACTION_CAMERA_BUTTON 按下照相時的拍照按鍵(硬體按鍵)時
Intent.ACTION_CLOSE_SYSTEM_DIALOGS 螢幕鎖屏
Intent.ACTION_CONFIGURATION_CHANGED 裝置目前設定被改變時(界面語言、裝置方向等)
Intent.ACTION_HEADSET_PLUG 插入耳機時
Intent.ACTION_MEDIA_BAD_REMOVAL 未正确移除SD卡但已取出來時(正确移除方法:設定–SD卡和裝置記憶體–解除安裝SD卡)
Intent.ACTION_MEDIA_CHECKING 插入外部儲存裝置(如SD卡)
Intent.ACTION_HEADSET_PLUG 插入耳機時
Intent.ACTION_PACKAGE_ADDED 成功安裝APK
Intent.ACTION_PACKAGE_REMOVED 成功删除APK
Intent.ACTION_REBOOT 重新開機裝置
Intent.ACTION_SCREEN_OFF 螢幕被關閉
Intent.ACTION_SCREEN_ON 螢幕被打開
Intent.ACTION_SHUTDOWN 關閉系統時
Intent.ACTION_REBOOT 重新開機裝置

參考文檔

BroadcastReceiver1

BroadcastReceiver2

BroadcastReceiver3

BroadcastReceiver4

BroadcastReceiver5

BroadcastReceiver6

BroadcastReceiver7