天天看點

Android四大元件之BroadcastReceiver知多少1、定義說明。2、使用場景。 3、内部機制(原理)。4、使用介紹。         5、注意事項。

說明:BroadcastReceiver——廣播接收者,是Android四大元件之一,在實際的開發過程中BroadcastReceiver的應用場景非常多,本篇文章将詳細講解一下BroadcastReceiver,如果各位碼友發現文中說明存在問題歡迎指正,CV操作請注明出處,謝謝!

1、定義說明。

    BroadcastReceiver即廣播接收者,是Android四大元件之一,是一個全局的監聽器。在Android中廣播分為廣播發送者和廣播接收者,廣播發送者(一般是其他的元件進行sendBroadcast操作),廣播接收者(BroadcastReceiver)對發送出來Broadcast進行過濾、接收和響應。

2、使用場景。

    Android不同元件間的通信(包括程序内和程序之間,同一App和不同App)。

    與Android系統通信(如開機、網絡狀态、安裝/解除安裝應用等)。

3、内部機制(原理)。

    設計模式:采用了觀察者模式,基于消息的釋出/訂閱事件模型,使得廣播的發送者和廣播的接收者進行解耦。

    參與角色:廣播(消息)發送者、廣播(消息)接收者、AMS(ActivityManagerService)

    實作步驟概況:

    1、廣播接收者通過Binder機制在AMS注冊。

    2、廣播發送者通過Binder機制在AMS發送廣播。

    3、AMS根據廣播發送者的要求,在注冊清單中,根據IntentFilter /Permission查找目标廣播接受者。

    4、AMS将廣播發送給目标廣播接收者的消息隊列中。

    5、廣播接收者通過消息隊列擷取消息,然後回調onReceive()。

4、使用介紹。

    4.1、廣播的接收。

    廣播接收者的使用大概分為三步:建立廣播接收者、注冊廣播接收者、根據需求實作邏輯。

    4.1.1 、建立廣播接收者。繼承BroadcastReceivre,複寫抽象方法onReceive()。

    public class XxxReceiver extends BroadcastReceiver {

        private static final String TAG = "XxxReceiver";

        public XxxReceiver() {

        }

        @Override

        public void onReceive(Context context, Intent intent) {

        //處理業務邏輯等,如發送Notification、啟動Service等

        }

    }

    注意:onReceive運作在UI線程中,是以,onReceive()方法不能執行耗時操作,否則将導緻ANR

    另外不要在此有開啟子線程的操作,會造成記憶體洩漏,如果需要請采用其他方式或者IntentService。

    4.1.2 、注冊廣播接收者(Android 8.0大部分靜态注冊廣播失效,僅剩下較少的系統廣播可以靜态注冊)。

     1、靜态注冊,即在清單檔案中為BroadcastReceiver進行注冊,使用<receive >标簽聲明,并在标簽内<intent-filter >标簽設定過濾器。

     這種形式的 BroadcastReceiver 的生命周期伴随着整個應用,如果這種方式處理的是系統廣播,那麼不管應用是否在運作,該廣播接收器都能接收到該廣播

     <receiver android:name=".XxxReceiver">

            <intent-filter>

                <action android:name="com.example.leisure.yyy" />

                <!--過濾屬性,隻有具有該屬性的廣播才會被接收-->

            </intent-filter>

        </receiver>

     <XxxReceiver 

        廣播接收者為四大元件之一,也具有下邊的較為常用的屬性

         android:exported="true"<!--外部應用是否可以調用,預設為true,如果不對外開放,建議false-->

         android:permission=""<!--具有相應權限的廣播發送者發送的廣播才能被此BroadcastReceiver所接收-->

         android:process=""<!--指定程序-->

         android:enabled=""<!--能否接收其他App的發出的廣播-->

     2、動态注冊。即在代碼中定義并設定好一個IntentFilter對象,然後在需要注冊的地方調用Context.registerReceiver()方法,調用Context.unregisterReceiver()可以取消注冊。

        @Override

        public void onCreate() {

            super.onCreate();//注冊廣播

            IntentFilter intentFilter = new IntentFilter();

            intentFilter.addAction("com.example.leisure.yyy");//

            receiver = new XxxReceiver();

            registerReceiver(receiver, intentFilter);

        }

        @Override

        public void onDestroy() {

            super.onDestroy();//取消注冊廣播

            unregisterReceiver(receiver);

        }

        注意:動态廣播的注冊和取消注冊須要成對出現。如果Activity/Fragment中建議在onResume()注冊、onPause()登出廣播因為onPause()在App死亡前一定會被執行,進而保證廣播在App死亡前一定會被登出,進而防止記憶體洩露。除非必要不建議在onCreate()/onDestory() 或 onStart()/onStop()注冊、登出,因為當系統因為記憶體不足(如優先級更高的應用需要記憶體)要回收Activity占用的資源時,Activity在執行完onPause()方法後就會被銷毀,有些生命周期方法onStop(),onDestory()就不會執行。

當再回到此Activity時,是從onCreate方法開始執行,造成記憶體洩漏。

4.2、廣播的發送。

4.2.1、廣播的分類,可分為5種:Normal Broadcast、System Broadcast、Sticky Broadcast、Local Broadcast。

        1、普通廣播(Normal Broadcast)。

        最為常用的廣播,一般需要添加action,聲明了對應的action的廣播接收者才能收到廣播,即onReceive()回調。如果添加了權限,則廣播接收者也需要在注冊的時候明确權限。

        Intent intent = new Intent();

        //對應BroadcastReceiver中intentFilter的action,

        intent.setAction("com.example.leisure.yyy");

        //發送廣播

        sendBroadcast(intent);

        2、系統廣播(System Broadcast)。

        系統廣播,不需要app去發送,由系統根據情況自動發送,app隻負責接收(如果需要)。

        3、有序廣播(Ordered Broadcast)。發送出去的廣播被廣播接收者按照先後順序接收,有序是針對廣播接收者而言的。

         廣播接受者接收的順序規則是按照Priority屬性值從大到小排序(同一Priority,動态注冊的廣播優先級大于靜态注冊的廣播);

         先接收的廣播接收者可以對廣播進行攔截,小優先級的廣播接收者将無法收到該廣播;

         先接收的廣播接收者可以對廣播進行修改,小優先級的廣播接收者将接收到被修改後的廣播。

        示例:

        Intent intent = new Intent("com.receiver.leisure.common");

        intent.putExtra("xxx", "有序廣播");

        sendOrderedBroadcast(intent, null);//發送有序廣播

        //此處忽略了注冊過程。

        public class OrderReceiverXxx extends BroadcastReceiver {//第一優先級

            public OrderReceiverXxx() {

            }

            @Override

            public void onReceive(Context context, Intent intent) {

                //取出Intent當中傳遞來的資料

                String msg = intent.getStringExtra("xxx");

                //向下一優先級的Receiver傳遞資料

                Bundle bundle = new Bundle();

                bundle.putString("yyy", "xxx修改了廣播");

                setResultExtras(bundle);

            }

        }

        public class OrderReceiverYyy extends BroadcastReceiver {//第二優先級

            public OrderReceiverYyy() {

            }

            @Override

            public void onReceive(Context context, Intent intent) {

                //取出上一優先級的Receiver傳遞來的資料

                String data = getResultExtras(true).getString("yyy");

                //攔截廣播

                abortBroadcast();

            }

        }

        public class OrderReceiverZzz extends BroadcastReceiver {//第三優先級

            public OrderReceiverZzz() {

            }

            @Override

            public void onReceive(Context context, Intent intent) {

                //收不到廣播了

            }

        }

        4、粘性廣播(Sticky Broadcast)。Android5.0(API 21)中已經失效,可忽略。

        5、本地廣播(Local Broadcast)。

    由于Android中的廣播可以跨程序(App)通信,不同的App注冊的廣播intent-filter可能會相同,也存在其他App根據intent-filter針對性的惡意發送某些廣播造成安全或者效率問題。

    Android内提供了本地廣播,廣播的發送者和接收者都同屬于一個App,提高了效率和安全性。

    針對普通廣播效率和安全性的問題,一般有兩種方式:

        1、注冊廣播時候将exported屬性設定為false;增設相應權限permission,用于權限驗證;發送廣播指定包名。

        2、建議使用本地廣播的形式。

        本地廣播是使用LocalBroadcastManager來對廣播進行管理,和普通廣播存在注冊、發送的方式的細微差别,除此之外都一樣。

        LocalBroadcastManager.getInstance(this).registerReceiver(BroadcastReceiver, IntentFilter)

        注冊Receiver

        LocalBroadcastManager.getInstance(this).unregisterReceiver(BroadcastReceiver);

        登出Receiver

        LocalBroadcastManager.getInstance(this).sendBroadcast(Intent)

        發送異步廣播

        LocalBroadcastManager.getInstance(this).sendBroadcastSync(Intent)

        發送同步廣播

5、注意事項。

1、不同注冊方式的廣播接收器回調OnReceive(Context context,Intent intent)中的context傳回值是不一樣的,靜态注冊的廣播是ReceiverRestrictedContext;動态注冊的廣播是Activity Context;本地廣播是Application Context。

繼續閱讀