Android本地廣播LocalBroadcastManager使用

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方法,需要傳遞兩個參數BroadcastReceiverIntentFilter
//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中註冊廣播,保存到mReceiversmActions
  • 通過sendBroadcast中匹配mActions中的BroadcastReceiver,將匹配到的對象保存到mPendingBroadcasts
  • 最終調用executePendingBroadcasts來發送廣播
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章