Android必知必會的四大組件 -- Broadcast Receiver篇

前言

廣播,在咱們的應用中起着一個很是重要的角色。就好比說咱們常用的IntentIntentFilter,就有着廣播的做用。java

在個人Android工具包項目中就集成了網絡廣播的動態註冊。android

思惟導圖

生命週期

由於沒有直接的圖示能夠上,並且Broadcast中並無onCreateonDestroy這樣方法,只能經過官方文檔驗證。 git

圖中的圈紅框的加粗文字大概意思就是,使用靜態廣播進行註冊,那麼每接受到一次信息,他就不復存在了,也就是須要重建。其它方式構建的生命週期,與關聯的 Activity中的具體操做相關。

在Android 8.0之後已經不在支持靜態廣播了github

兩種廣播

public class NetworkReceiver extends BroadcastReceiver {
   @Override
   public void onReceive(Context context, Intent intent) {
       if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION) && App.getInstance() != null) {
           App.getInstance().notifyObservers(isNetConnected(context));
       }
   }
}
複製代碼

雖然是兩種廣播形式,可是他們一樣要幹一件事情,就是繼承BroadcastReceiver,並重寫onReceive()方法。安全

全局廣播

這個廣播一樣可使用在應用內,可是這種廣播的安全性有待質疑。網絡

// 消息傳遞
sendBroadcast(Intent);
複製代碼
  • 靜態廣播註冊
<receiver android:name="com.clericyi.basehelper.network.NetworkReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BATTERY_LOW"/>
    </intent-filter>
</receiver>
複製代碼
  • 動態廣播註冊

和靜態廣播不一樣的地方,動態廣播註冊完之後須要進行註銷操做。異步

// 註冊
networkReceiver = new NetworkReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(networkReceiver, intentFilter);

// 註銷(若是沒有註銷,將會發生內存泄漏)
unregisterReceiver(networkReceiver);
複製代碼

應用內廣播

  1. 優勢:
    • 發送的廣播只會在本身的App內傳播,不會泄漏給其餘App,保障了數據的安全性。
    • 沒法接受到其餘App的廣播,也就省去各類麻煩事。
    • 相較於全局廣播效率更高。
  2. 使用方法
//註冊
networkReceiver = new NetworkReceiver();
localBroadcastManager = LocalBroadcastManager.getInstance(this); // --> 以單例模式進行建立
localBroadcastManager.registerReceiver(networkReceiver, new IntentFilter("須要去過濾的信息"));

// 發送消息
localBroadcastManager.sendBroadcast(Intent);

// 註銷
localBroadcastManager.unregisterReceiver(networkReceiver);
複製代碼

LocalBroadcastManager源碼導讀

爲何要導讀LocalBroadcastManager源碼呢?ide

實際上是想讓讀者們知道LocalBroadcastManager使用並非Binder機制來完成通訊的。函數

getInstance()

public static LocalBroadcastManager getInstance(@NonNull Context context) {
        synchronized (mLock) {
            if (mInstance == null) {
                mInstance = new LocalBroadcastManager(context.getApplicationContext()); // 1 -->
            }
            return mInstance;
        }
    }
// 由註釋1直接調用的方法 
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);
                }
            }
        };
    }
複製代碼

那這裏就是很清楚的知道,這是一個以DCL的方式,來直接完成對單例的建立,而在構造函數中,定義了一個Handler工具

那咱們就來作一個猜想,咱們在應用內的廣播本質實際上是基於一個Handler的一異步傳輸機制。爲了驗證!!咱們就須要去了解他的sendBroadcast(Intent)方法。

sendBroadcast(Intent)

public boolean sendBroadcast(@NonNull Intent intent) {
        synchronized (mReceivers) {
            // 拿到傳遞過來的Intent中保存的數據
            final String action = intent.getAction();
            final String type = intent.resolveTypeIfNeeded(
                    mAppContext.getContentResolver());
            final Uri data = intent.getData();
            final String scheme = intent.getScheme();
            final Set<String> categories = intent.getCategories();

            // 。。。。。
            
            // 獲取配置的Action
            ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
            if (entries != null) {
                if (debug) Log.v(TAG, "Action list: " + entries);

                ArrayList<ReceiverRecord> receivers = null;
                // 。。。。。 對變量receivers的一些列操做。

                // 存在接受對象時,將數據經過Handler的方式傳遞出去。
                if (receivers != null) {
                    for (int i=0; i<receivers.size(); i++) {
                        receivers.get(i).broadcasting = false;
                    }
                    mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
                    if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
                        mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
                    }
                    return true;
                }
            }
        }
        return false;
    }
複製代碼

經過代碼已經成功驗證了,其實LocalBroadcast最終基於的數據傳輸機制就是咱們的Handler,這就是和應用間廣播最大的不一樣之處了。

總結

  1. 動態廣播和靜態廣播的區別?
    • 靜態廣播:廣播一直存在,消耗資源較大,耗電量大。
    • 動態廣播:廣播的生命週期較爲靈活,資源消耗少。響應速度快於靜態廣播。
  2. 廣播一樣會引起ANR的慘狀,廣播的耗時操做時長不容許超過10s。並且廣播內通常也不會像ServiceActivity同樣會使用Thread來完成咱們的耗時操做。
  3. 全局和應用內的廣播二者的註冊方式其實類似,可是針對的場景不一樣。若是須要網絡、電池等服務,你就須要全局廣播;若是你只須要應用內通訊,那麼你只須要應用內廣播。
  4. 應用內廣播(LocalBroadcast)使用的Handler的消息傳輸機制;應用間廣播或者說是進程間廣播(Broadcast)使用的則是Binder的機制。

以上就是個人學習成果,若是有什麼我沒有思考到的地方或是文章內存在錯誤,歡迎與我分享。


相關文章推薦:

Android必知必會的四大組件 -- Service篇

Glide都在用的LruCache,你會幾分?

Android事件分發機制,你瞭解過嗎?

相關文章
相關標籤/搜索