LocalBroadcastManager 簡介
學習Android的同鞋一定知道四大組件,四大組件有:
四大組件中的BroadcastReceiver是全局廣播,即發送廣播時可能被多個App接收到,有時候從安全角度考慮,爲了數據的安全傳遞,是不是有辦法避免被多個App接收廣播,於是有了本地廣播,本地廣播只會在自己的App內傳播,用於在同一個應用內的不同組件間發送Broadcast進行通信。使用本地廣播,需要用到support庫中的LocalBroadcastManager。
LocalBroadcastManager使用
這裏先列出LocalBroadcastManager中常用的方法:
LocalBroadcastManager中方法 | 說明 |
---|---|
getInstance(Context context) | 獲取本地廣播實例 |
registerReceiver(BroadcastReceiver receiver, IntentFilter filter) | 註冊廣播 |
unregisterReceiver(BroadcastReceiver receiver) | 解註冊 |
sendBroadcast(Intent intent) | 發送廣播(內部使用Handler,保證onReceive在主線程中調用) |
sendBroadcastSync(Intent intent) | 同步發送廣播,如果消息隊列中消息太多,會導致廣播接收者接收廣播太慢,可使用這個方法同步發送廣播 |
- 獲取LocalBroadcastManager對象
LocalBroadcastManager被設計爲一個單例類,通過getInstance
方法獲取實例,參數需要一個上下文對象
// java
LocalBroadcastManager localManager= LocalBroadcastManager.getInstance(mContext);
// kotlin
val localManager = LocalBroadcastManager.getInstance(mContext)
- 註冊觀察者
和全局廣播的思想一樣,如果要接收廣播,那麼需要先註冊一個廣播,才能接收到匹配的廣播。本地廣播不能通過在AndroidManifest文件中靜態聲明註冊,只能通過動態註冊的方法註冊,這裏註冊時需要調用registerReceiver
方法,需要傳遞兩個參數BroadcastReceiver
和IntentFilter
//java
LocalBroadcastManager localManager = LocalBroadcastManager.getInstance(mContext);
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "收到廣播", Toast.LENGTH_SHORT).show();
}
};
IntentFilter intentFilter = new IntentFilter("LocalBroadcastManager-test");
localManager.registerReceiver(receiver, intentFilter);//註冊廣播
//kotlin
val localManager = LocalBroadcastManager.getInstance(mContext)
val broadReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(context, "收到廣播", Toast.LENGTH_SHORT).show()
}
}
val intentFilter = IntentFilter("LocalBroadcastManager-test")
localManager.registerReceiver(broadReceiver, intentFilter)
- 通過本地發送廣播
通過上面定義BroadcastReceiver來接收廣播處理,現在可以發送廣播試試了
//java
localManager.sendBroadcast(new Intent("LocalBroadcastManager-test"));
//kotlin
localManager.sendBroadcast(Intent("LocalBroadcastManager-test"))
LocalBroadcastManager 源碼分析
LocalBroadcastManager位於android.support.v4.content包下
因爲本地廣播基於觀察者模式設計,所以將LocalBroadcastManager設計成單例,被觀察者只有一個嘛,以下是獲取實例和私有構造方法
// 忽略部分代碼
public static LocalBroadcastManager getInstance(@NonNull Context context) {
Object var1 = mLock;
synchronized(mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
private LocalBroadcastManager(Context context) {
this.mAppContext = context;
//UI線程的Looper,說明可以在子線程獲取實例、發送廣播
this.mHandler = new Handler(context.getMainLooper()) {
public void handleMessage(Message msg) {
switch(msg.what) {
case 1:
LocalBroadcastManager.this.executePendingBroadcasts();
break;
default:
super.handleMessage(msg);
}
}
};
}
在LocalBroadcastManager中有兩個內部靜態類,封裝了BroadcastReceiver和IntentFilter
// 忽略部分代碼
private static final class ReceiverRecord {
final IntentFilter filter;//註冊廣播時的intentFilter
final BroadcastReceiver receiver;//註冊廣播時的broadcastReceiver
boolean broadcasting;//是否添加到廣播隊列
boolean dead;//死亡標識
ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver) {
this.filter = _filter;
this.receiver = _receiver;
}
public String toString() {
StringBuilder builder = new StringBuilder(128);
builder.append("Receiver{");
builder.append(this.receiver);
builder.append(" filter=");
builder.append(this.filter);
if (this.dead) {
builder.append(" DEAD");
}
builder.append("}");
return builder.toString();
}
}
private static final class BroadcastRecord {
final Intent intent;//發送廣播的intent
final ArrayList<LocalBroadcastManager.ReceiverRecord> receivers;//發送廣播intent匹配的receivers
BroadcastRecord(Intent _intent, ArrayList<LocalBroadcastManager.ReceiverRecord> _receivers) {
this.intent = _intent;
this.receivers = _receivers;
}
}
下面看下注冊觀察都和解註冊的代碼
// 保存所有註冊BroadcastReceiver的HashMap
private final HashMap<BroadcastReceiver, ArrayList<LocalBroadcastManager.ReceiverRecord>> mReceivers = new HashMap();
//保存所有註冊BroadcastReceiver中IntentFilter的action
private final HashMap<String, ArrayList<LocalBroadcastManager.ReceiverRecord>> mActions = new HashMap();
public void registerReceiver(@NonNull BroadcastReceiver receiver, @NonNull IntentFilter filter) {
HashMap var3 = this.mReceivers;
synchronized(this.mReceivers) {
// 創建一個LocalBroadcastManager.ReceiverRecord對象
LocalBroadcastManager.ReceiverRecord entry = new LocalBroadcastManager.ReceiverRecord(filter, receiver);
// 從mReceivers中獲取是否存在的LocalBroadcastManager.ReceiverRecord對象
ArrayList<LocalBroadcastManager.ReceiverRecord> filters = (ArrayList)this.mReceivers.get(receiver);
if (filters == null) {
//如果mReceivers不存在要註冊的receiver,則創建一個新的,保存到Mreceivers中
filters = new ArrayList(1);
this.mReceivers.put(receiver, filters);//保存receiver對應的LocalBroadcastManager.ReceiverRecord
}
filters.add(entry);
for(int i = 0; i < filter.countActions(); ++i) {
// 遍歷獲取filter中所有的action,保存到mActions中
String action = filter.getAction(i);
ArrayList<LocalBroadcastManager.ReceiverRecord> entries = (ArrayList)this.mActions.get(action);
if (entries == null) {
entries = new ArrayList(1);
this.mActions.put(action, entries);//保存action對應的LocalBroadcastManager.ReceiverRecord
}
entries.add(entry);
}
}
}
public void unregisterReceiver(@NonNull BroadcastReceiver receiver) {
HashMap var2 = this.mReceivers;
synchronized(this.mReceivers) {
//mReceivers中移除已註冊的receiver
ArrayList<LocalBroadcastManager.ReceiverRecord> filters = (ArrayList)this.mReceivers.remove(receiver);
if (filters != null) {//移除成功不爲null
for(int i = filters.size() - 1; i >= 0; --i) {
LocalBroadcastManager.ReceiverRecord filter = (LocalBroadcastManager.ReceiverRecord)filters.get(i);
filter.dead = true;//死亡標識
for(int j = 0; j < filter.filter.countActions(); ++j) {
String action = filter.filter.getAction(j);
ArrayList<LocalBroadcastManager.ReceiverRecord> receivers = (ArrayList)this.mActions.get(action);
if (receivers != null) {
for(int k = receivers.size() - 1; k >= 0; --k) {
LocalBroadcastManager.ReceiverRecord rec = (LocalBroadcastManager.ReceiverRecord)receivers.get(k);
if (rec.receiver == receiver) {
rec.dead = true;//標識死亡
receivers.remove(k);//先移除mAction中action對應List中的
}
}
if (receivers.size() <= 0) {
this.mActions.remove(action);//如果action對應的list爲0,移除mAction中的action
}
}
}
}
}
}
}
發送廣播的邏輯
public boolean sendBroadcast(@NonNull Intent intent) {
HashMap var2 = this.mReceivers;
synchronized(this.mReceivers) {
String action = intent.getAction();
String type = intent.resolveTypeIfNeeded(this.mAppContext.getContentResolver());
Uri data = intent.getData();
String scheme = intent.getScheme();
Set<String> categories = intent.getCategories();
boolean debug = (intent.getFlags() & 8) != 0;
if (debug) {
Log.v("LocalBroadcastManager", "Resolving type " + type + " scheme " + scheme + " of intent " + intent);
}
// 獲取匹配的action的ReceiverRecord對象
ArrayList<LocalBroadcastManager.ReceiverRecord> entries = (ArrayList)this.mActions.get(intent.getAction());
if (entries != null) {
if (debug) {
Log.v("LocalBroadcastManager", "Action list: " + entries);
}
ArrayList<LocalBroadcastManager.ReceiverRecord> receivers = null;
int i;
//遍歷匹配到action的廣播
for(i = 0; i < entries.size(); ++i) {
LocalBroadcastManager.ReceiverRecord receiver = (LocalBroadcastManager.ReceiverRecord)entries.get(i);
if (debug) {
Log.v("LocalBroadcastManager", "Matching against filter " + receiver.filter);
}
if (receiver.broadcasting) {
if (debug) {
Log.v("LocalBroadcastManager", " Filter's target already added");
}
} else {
int match = receiver.filter.match(action, type, scheme, data, categories, "LocalBroadcastManager");
if (match >= 0) {
if (debug) {
Log.v("LocalBroadcastManager", " Filter matched! match=0x" + Integer.toHexString(match));
}
if (receivers == null) {
receivers = new ArrayList();
}
receivers.add(receiver);
receiver.broadcasting = true;
} else if (debug) {
String reason;
switch(match) {
case -4:
reason = "category";
break;
case -3:
reason = "action";
break;
case -2:
reason = "data";
break;
case -1:
reason = "type";
break;
default:
reason = "unknown reason";
}
Log.v("LocalBroadcastManager", " Filter did not match: " + reason);
}
}
}
if (receivers != null) {
for(i = 0; i < receivers.size(); ++i) {
((LocalBroadcastManager.ReceiverRecord)receivers.get(i)).broadcasting = false;
}
// 添加到廣播隊列
this.mPendingBroadcasts.add(new LocalBroadcastManager.BroadcastRecord(intent, receivers));
if (!this.mHandler.hasMessages(1)) {
//發送消息
this.mHandler.sendEmptyMessage(1);
}
return true;
}
}
return false;
}
}
sendBroadcastSync方法有些不同,可自行查看源碼
下面來看下處理廣播的邏輯
void executePendingBroadcasts() {
while(true) {
HashMap var2 = this.mReceivers;
LocalBroadcastManager.BroadcastRecord[] brs;
synchronized(this.mReceivers) {
int N = this.mPendingBroadcasts.size();
if (N <= 0) {
return;
}
brs = new LocalBroadcastManager.BroadcastRecord[N];
this.mPendingBroadcasts.toArray(brs); //轉換array
this.mPendingBroadcasts.clear();//清空操作
}
for(int i = 0; i < brs.length; ++i) {
LocalBroadcastManager.BroadcastRecord br = brs[i];
int nbr = br.receivers.size();
// 遍歷回調onReceiver方法
for(int j = 0; j < nbr; ++j) {
LocalBroadcastManager.ReceiverRecord rec = (LocalBroadcastManager.ReceiverRecord)br.receivers.get(j);
if (!rec.dead) {//如果沒有dead調用onReceiver方法
rec.receiver.onReceive(this.mAppContext, br.intent);
}
}
}
}
}
到這裏就把整個邏輯分析了,主要邏輯有:
- 在LocalBroadcastManager中通過
registerReceiver
中註冊廣播,保存到mReceivers
和mActions
中 - 通過
sendBroadcast
中匹配mActions
中的BroadcastReceiver,將匹配到的對象保存到mPendingBroadcasts
中 - 最終調用
executePendingBroadcasts
來發送廣播