前言
廣播,在我們的應用中起著一個非常重要的角色。就比如說我們經常使用的Intent
、IntentFilter
,就有著廣播的作用。
在我的Android工具包專案中就整合了網路廣播的動態註冊。
思維導圖
生命週期
因為沒有直接的圖示可以上,而且Broadcast中並沒有onCreate
、onDestroy
這樣方法,只能通過官方文件驗證。
Activity
中的具體操作相關。
在Android 8.0以後已經不在支援靜態廣播了
兩種廣播
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);
複製程式碼
應用內廣播
- 優點:
- 傳送的廣播只會在自己的App內傳播,不會洩漏給其他App,保障了資料的安全性。
- 無法接受到其他App的廣播,也就省去各種麻煩事。
- 相較於全域性廣播效率更高。
- 使用方法
//註冊
networkReceiver = new NetworkReceiver();
localBroadcastManager = LocalBroadcastManager.getInstance(this); // --> 以單例模式進行建立
localBroadcastManager.registerReceiver(networkReceiver, new IntentFilter("需要去過濾的資訊"));
// 傳送訊息
localBroadcastManager.sendBroadcast(Intent);
// 登出
localBroadcastManager.unregisterReceiver(networkReceiver);
複製程式碼
LocalBroadcastManager原始碼導讀
為什麼要導讀LocalBroadcastManager
原始碼呢?
其實是想讓讀者們知道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
,這就是和應用間廣播最大的不同之處了。
總結
- 動態廣播和靜態廣播的區別?
- 靜態廣播:廣播一直存在,消耗資源較大,耗電量大。
- 動態廣播:廣播的生命週期較為靈活,資源消耗少。響應速度快於靜態廣播。
- 廣播同樣會引發
ANR
的慘狀,廣播的耗時操作時長不允許超過10s。而且廣播內一般也不會像Service
和Activity
一樣會使用Thread
來完成我們的耗時操作。 - 全域性和應用內的廣播兩者的註冊方式其實相似,但是針對的場景不同。如果需要網路、電池等服務,你就需要全域性廣播;如果你只需要應用內通訊,那麼你只需要應用內廣播。
- 應用內廣播(
LocalBroadcast
)使用的Handler
的訊息傳輸機制;應用間廣播或者說是程式間廣播(Broadcast
)使用的則是Binder
的機制。
以上就是我的學習成果,如果有什麼我沒有思考到的地方或是文章記憶體在錯誤,歡迎與我分享。
相關文章推薦: