LocalBroadcastManager分析

在Android系統中,BroadcastReceiver的設計初衷就是從全局考慮的,能夠方便應用程序和系統、應用程序之間、應用程序內的通訊,因此對單個應用程序而言BroadcastReceiver是存在安全性問題的,相應問題及解決以下:html

一、當應用程序發送某個廣播時系統會將發送的Intent與系統中全部註冊的BroadcastReceiver的IntentFilter進行匹配,若匹配成功則執行相應的onReceive函數。能夠經過相似sendBroadcast(Intent, String)的接口在發送廣播時指定接收者必須具有的permission。或經過Intent.setPackage設置廣播僅對某個程序有效。java

二、當應用程序註冊了某個廣播時,即使設置了IntentFilter仍是會接收到來自其餘應用程序的廣播進行匹配判斷。對於動態註冊的廣播能夠經過相似registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler)的接口指定發送者必須具有的permission,對於靜態註冊的廣播能夠經過android:exported="false"屬性表示接收者對外部應用程序不可用,即不接受來自外部的廣播。android

LocalBroadcastManager是Android Support包提供了一個工具,是用來在同一個應用內的不一樣組件間發送Broadcast的。數組

使用LocalBroadcastManager有以下好處:安全

  • 發送的廣播只會在本身App內傳播,不會泄露給其餘App,確保隱私數據不會泄露
  • 其餘App也沒法向你的App發送該廣播,不用擔憂其餘App會來搞破壞
  • 比系統全局廣播BroadcastReceiver更加高效

LocalBroadcastManager 的使用跟通常 BroadcastReceiver 差異不大。併發

三、實現

(1) 構造函數ide

public static LocalBroadcastManager getInstance(Context context) {
    synchronized (mLock) {
        if (mInstance == null) {
            mInstance = new LocalBroadcastManager(context.getApplicationContext());
        }
        return mInstance;
    }
}

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);
            }
        }
    };
}

注意的是基於主線程的 Looper 新建了一個 Handler,handleMessage中會調用接收器對廣播的消息進行處理,也是 LocalBroadcastManager 的核心部分,具體見後面executePendingBroadcasts()介紹。函數

(2) 註冊接收器工具

HashMap<BroadcastReceiver, ArrayList<IntentFilter>> mReceivers
            = new HashMap<BroadcastReceiver, ArrayList<IntentFilter>>();
HashMap<String, ArrayList<ReceiverRecord>> mActions
            = new HashMap<String, ArrayList<ReceiverRecord>>();

public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    synchronized (mReceivers) {
        ReceiverRecord entry = new ReceiverRecord(filter, receiver);
        ArrayList<IntentFilter> filters = mReceivers.get(receiver);
        if (filters == null) {
            filters = new ArrayList<IntentFilter>(1);
            mReceivers.put(receiver, filters);
        }
        filters.add(filter);
        for (int i=0; i<filter.countActions(); i++) {
            String action = filter.getAction(i);
            ArrayList<ReceiverRecord> entries = mActions.get(action);
            if (entries == null) {
                entries = new ArrayList<ReceiverRecord>(1);
                mActions.put(action, entries);
            }
            entries.add(entry);
        }
    }
}

mReceivers 存儲廣播和過濾器信息,以BroadcastReceiver做爲 key,IntentFilter鏈表做爲 value。
mReceivers 是接收器和IntentFilter的對應表,主要做用是方便在unregisterReceiver(…)取消註冊,同時做爲對象鎖限制註冊接收器、發送廣播、取消接收器註冊等幾個過程的併發訪問。oop

mActions 以Action爲 key,註冊這個ActionBroadcastReceiver鏈表爲 value。mActions 的主要做用是方便在廣播發送後快速獲得能夠接收它的BroadcastReceiver

(3) 發送廣播

public boolean sendBroadcast(Intent intent) {
    synchronized (mReceivers) {
        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();
        ……
        ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
        if (entries != null) {
            if (debug) Log.v(TAG, "Action list: " + entries);

            ArrayList<ReceiverRecord> receivers = null;
            for (int i=0; i<entries.size(); i++) {
                ReceiverRecord receiver = entries.get(i);
                if (receiver.broadcasting) {
                    if (debug) {
                        Log.v(TAG, "  Filter's target already added");
                    }
                    continue;
                }

                int match = receiver.filter.match(action, type, scheme, data,
                        categories, "LocalBroadcastManager");
                if (match >= 0) {
                    if (debug) Log.v(TAG, "  Filter matched!  match=0x" +
                            Integer.toHexString(match));
                    if (receivers == null) {
                        receivers = new ArrayList<ReceiverRecord>();
                    }
                    receivers.add(receiver);
                    receiver.broadcasting = true;
                } else {
                    ……
                }
            }

            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;
}

先根據ActionmActions中取出ReceiverRecord列表,循環每一個ReceiverRecord判斷 filter 和 intent 中的 action、type、scheme、data、categoried 是否 match,是的話則保存到receivers列表中,發送 what 爲MSG_EXEC_PENDING_BROADCASTS的消息,經過 Handler 去處理。

(4) 消息處理

private void executePendingBroadcasts() {
    while (true) {
        BroadcastRecord[] brs = null;
        synchronized (mReceivers) {
            final int N = mPendingBroadcasts.size();
            if (N <= 0) {
                return;
            }
            brs = new BroadcastRecord[N];
            mPendingBroadcasts.toArray(brs);
            mPendingBroadcasts.clear();
        }
        for (int i=0; i<brs.length; i++) {
            BroadcastRecord br = brs[i];
            for (int j=0; j<br.receivers.size(); j++) {
                br.receivers.get(j).receiver.onReceive(mAppContext, br.intent);
            }
        }
    }
}

mPendingBroadcasts轉換爲數組BroadcastRecord,循環每一個receiver,調用其onReceive函數,這樣便完成了廣播的核心邏輯。

(5) 取消註冊

public void unregisterReceiver(BroadcastReceiver receiver) {
    synchronized (mReceivers) {
        ArrayList<IntentFilter> filters = mReceivers.remove(receiver);
        if (filters == null) {
            return;
        }
        for (int i=0; i<filters.size(); i++) {
            IntentFilter filter = filters.get(i);
            for (int j=0; j<filter.countActions(); j++) {
                String action = filter.getAction(j);
                ArrayList<ReceiverRecord> receivers = mActions.get(action);
                if (receivers != null) {
                    for (int k=0; k<receivers.size(); k++) {
                        if (receivers.get(k).receiver == receiver) {
                            receivers.remove(k);
                            k--;
                        }
                    }
                    if (receivers.size() <= 0) {
                        mActions.remove(action);
                    }
                }
            }
        }
    }
}

到此爲止咱們便很是清晰了:
(1) LocalBroadcastManager 的核心實現實際仍是 Handler,只是利用到了 IntentFilter 的 match 功能,至於 BroadcastReceiver 換成其餘接口也無所謂,順便利用了現成的類和概念而已。
(2) 由於是 Handler 實現的應用內的通訊,天然安全性更好,效率更高。

(3) 原理其實很簡單,就是register時,將要執行的Broadcast保存起來,sendBroadcast時,遍歷執行,之因此使用Handler,是由於要保證onReceive方法的執行時在主線程。建立一個使用MainLooper的Handler,這樣,即便sendBroadcast方法是在子線程,經過Handler後,仍是在主線程執行的onReceive方法。

相關文章
相關標籤/搜索