Android系統源碼分析-Broadcast註冊和註銷

距離上一篇博客進程的加載過了好久的時間,這中間換了一份工做,加入了新的團隊,也開始了新的項目,比較忙,因此最近纔有時間將四大組件之一的廣播原理看完,最近一段時間會相繼把四大組件分析寫完,讓咱們對四大組件有更深的瞭解。原本想一篇把廣播的內容寫完,可是發現要解釋的代碼比較多,因此仍是分開來說,那麼這篇先分析廣播的註冊和註銷,下一篇再分析廣播的發送。java

Broadcast的註冊

註冊廣播時序圖

Step-1:註冊廣播入口ContextImpl.registerReceiver:

@Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, null, null);
    }
複製代碼

而後調用registerReceiver複寫方法:緩存

@Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext());
    }
複製代碼

Step-2:調用registerReceiverInternal方法:

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) {
        IIntentReceiver rd = null;
        // 須要註冊的廣播接收器不爲null
        if (receiver != null) {
            if (mPackageInfo != null && context != null) {
                if (scheduler == null) {
                    // 獲取主線程的Handler,mMainThread是描述當前應用程序進程的
                    scheduler = mMainThread.getHandler();
                }
                // 將廣播接收者receiver封裝成一個實現了IIntentReceiver接口的Binder對象rd(ReceiverDispatcher)
                rd = mPackageInfo.getReceiverDispatcher(
                        receiver, context, scheduler,
                        mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    // 獲取主線程的Handler
                    scheduler = mMainThread.getHandler();
                }
                // 將廣播接收者receiver封裝成一個實現了IIntentReceiver接口的Binder對象rd(ReceiverDispatcher)
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            // 調用ActivityManagerProxy的registerReceiver,最終經過mRemote.transact方法傳遞到
            // ActivityManagerService中的registerReceiver方法
            final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
            ...
            return intent;
        } catch (RemoteException e) {
            ...
        }
    }
複製代碼

mPackageInfo是LoadedApk類型對象,這個對象是在一個應用啓動的時候建立的。微信

Step-3:LoadedApk.getReceiverDispatcher方法:

// 每個註冊過廣播接收者的Activity組件在LaodApk類中都有一個對應的ReceiverDispatcher對象,它負責
    // 將這個被註冊的廣播接收者與註冊它的Activity組件關聯在一塊兒。這些ReceiverDispatcher對象保存在一個
    // HashMap中,而且以它們所關聯的廣播接收者爲關鍵字。最後用來保存這些ReceiverDispatcher對象的HashMap
    // 又以它們所關聯的Activity組件的Context接口爲關鍵字保存在LoadApk類的成員變量mReceivers中
    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, Context context, Handler handler, Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
            // 是否是註冊廣播
            if (registered) {
                // 查找有沒有對應的廣播接收者對象列表
                map = mReceivers.get(context);
                if (map != null) {
                    // 查找是否存在該廣播接收者對應的ReceiverDispatcher對象
                    rd = map.get(r);
                }
            }
            if (rd == null) {// 不存在
                // 初始化廣播接收器調度員
                rd = new ReceiverDispatcher(r, context, handler,
                        instrumentation, registered);
                if (registered) {
                    if (map == null) {
                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                        mReceivers.put(context, map);
                    }
                    // 緩存ReceiverDispatcher
                    map.put(r, rd);
                }
            } else {
                // 驗證廣播分發者的Context和Handler是否一致。
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();
        }
    }
複製代碼

這裏主要是將廣播接收者receiver封裝成一個實現了IIntentReceiver接口的Binder對象rd,而後將其放置到LoadedApk對象中的mReceivers中保存起來。app

再回到上面代碼中,將生成的實現了IIntentReceiver接口的Binder對象rd經過mRemote.transact方法傳遞到ActivityManagerService中的registerReceiver方法,由於四大組件的消息傳遞都是經過這種方式實現的。異步

Step-7:ActivityManagerProxy.registerReceiver

public Intent registerReceiver(IApplicationThread caller, String packageName, IIntentReceiver receiver, IntentFilter filter, String perm, int userId) throws RemoteException {
        ...
        // 經過內部的一個Binder代理對象mRemote向AMS發送一個類型爲REGISTER_RECEIVER_TRANSACTION的進程
        // 間通訊請求
        mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
        ...
        return intent;
    }
複製代碼

Step-8:ActivityManagerService.registerReceiver

經過上面的mRemote.transact方法傳遞到ActivityManagerService中對應的方法:async

/** * 粘性廣播(Sticky):一個粘性廣播被髮送到AMS後,就會一直保存在AMS中,直到AMS下次再接收到另一個 * 同類型的粘性廣播爲止。一個Activity組件在向AMS註冊接收某一種烈性的廣播時,若是AMS內部切好保存這個 * 這種類型的粘性廣播,那麼AMS就會將這個粘性廣播返回給Activity組件,以便它能夠知道系統上一次發出的它 * 所感興趣的廣播內容。咱們能夠經過sendStrickyBroadcast向AMS發送粘性廣播 */
public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
        ...
        ArrayList<Intent> stickyIntents = null;
        ProcessRecord callerApp = null;
        int callingUid;
        int callingPid;
        synchronized (this) {
            if (caller != null) {
                // 根據caller從ProcessRecord緩存列表中查詢ProcessRecord對象caller,用來描述正在請求
                // AMS註冊廣播接收者的一個Activity組件所運行在的應用程序進程
                callerApp = getRecordForAppLocked(caller);
                if (callerApp == null) {// 沒有對應進程,不能註冊廣播
                    ...//拋出異常
                }
                ...
            } else {
                ...
            }

            // 獲取註冊廣播的用戶的userId(UserController是多用戶功能的用戶管理,一些系統包含訪客模式,或者多用戶,每一個用戶就會有一個id)
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

            // 獲取須要註冊廣播的IntentFilter中全部的action
            Iterator<String> actions = filter.actionsIterator();
            // 若是註冊廣播沒有Action則添加一個null
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }

            // Activity組件在註冊一個廣播接收者時,並非直接將這個廣播接收者註冊到了AMS中,而是將與它關聯
            // 的一個InnerReceiver對象註冊到了AMS中。當AMS接收到一個廣播時,它就會根據這個廣播的類型在內
            // 部知道對應的InnerReceiver對象,而後再經過這個對象將這個廣播發送給對應的廣播接收者。AMS中每
            // 一個廣播接收者都是使用一個BroadcastFilter對象來描述的,而每個BroadcastFilter對象又是根
            // 據它所描述的廣播接收者所關聯的一個BroadcastFilter對象,以及所要接受的廣播類型來建立。因爲在
            // 一個應用程序中,不一樣的Activity組件可能會使用同一個BroadcastFilter對象來註冊不一樣的廣播接收
            // 者,所以AMS會使用一個ReceiverList列表來保存這些使用了相同InnerReceiver對象來註冊的廣播接
            // 收者,而且以它們所使用的InnerReceiver對象爲關鍵字。

            // Collect stickies of users
            // 收集與註冊用戶userId相關的全部已經被廣播過的Intent,存儲在stickyIntents中
            // 包含全部用戶以及註冊廣播進程對應的用戶
            // 第一個UserHandle.USER_ALL表示設備上全部的用戶,
            // 第二個是callingUid對應用戶的userId(當前用戶的userId)
            int[] userIds = {UserHandle.USER_ALL, UserHandle.getUserId(callingUid)};
            // 這裏只經過action進行過濾
            while (actions.hasNext()) {
                String action = actions.next();
                // 遍歷與調度進程相關的用戶id
                for (int id : userIds) {
                    // 根據userId查詢已經發送過的對應的Intent列表
                    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                    // 若是已經發送的Intent裏包含上面要註冊的廣播的action的Intent,將其保存到stickyIntents中
                    if (stickies != null) {
                        // 根據action查詢Intent列表
                        ArrayList<Intent> intents = stickies.get(action);
                        if (intents != null) {
                            if (stickyIntents == null) {
                                stickyIntents = new ArrayList<Intent>();
                            }
                            stickyIntents.addAll(intents);
                        }
                    }
                }
            }
        }

        // 下面對經過action過濾出來粘性廣播的Intent列表,包括:action,type,scheme,data,categories
        ArrayList<Intent> allSticky = null;
        if (stickyIntents != null) {
            final ContentResolver resolver = mContext.getContentResolver();
            // Look for any matching sticky broadcasts...
            for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                Intent intent = stickyIntents.get(i);
                // 查找與IntentFilter匹配的Intent
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
                    allSticky.add(intent);
                }
            }
        }

        ...
        if (receiver == null) {// 若是廣播接收器爲null,則直接返回第一個Intent結束註冊
            return sticky;
        }

        synchronized (this) {
            // 首先判斷當前進程是否還活着
            if (callerApp != null && (callerApp.thread == null
                    || callerApp.thread.asBinder() != caller.asBinder())) {
                // Original caller already died(註冊失敗)
                return null;
            }
            // 首先從緩存中查找註冊的receiver對應的ReceiverList(ArrayList<BroadcastFilter>),
            // 第一次註冊爲null,receiver對應的是一個BroadcastFilter列表,也就是說能夠經過調用
            // registerReceiver來爲receiver註冊不一樣的廣播條件。
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            // 緩存中沒有,說明尚未註冊過,若是有說明已經註冊過了,不須要再添加
            if (rl == null) {
                // 若是沒有就建立新的廣播接收者(裏面包含廣播過濾器列表)列表
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    rl.app.receivers.add(rl);
                } else {
                    ...
                }
                // 這裏面最關鍵的就是下面將receiver以及對應的ReceiverList列表放到mRegisteredReceivers中
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } 
            ...
            // 建立BroadcastFilter對象bf,用來描述正在註冊的廣播接收者,並添加到ReceiverList隊列rl中
            // 以及mReceiverResolver中
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId);
            rl.add(bf);
            ...
            // 添加到已註冊接收器的廣播解析器中,註冊完成
            mReceiverResolver.addFilter(bf);

            // Enqueue broadcasts for all existing stickies that match
            // this filter.
            // 上面註冊結束之後,若是篩選出了與當前註冊的IntentFilter匹配的sticky廣播的Intent列表,
            // 就將全部匹配的Intent逐條發送廣播給當前的註冊者receiver,能夠看到這裏的接受者receivers
            // 裏面就只有當前建立的一個BroadcastFilter,也就是當前的註冊者。
            if (allSticky != null) {
                ArrayList receivers = new ArrayList();
                receivers.add(bf);

                final int stickyCount = allSticky.size();
                for (int i = 0; i < stickyCount; i++) {
                    Intent intent = allSticky.get(i);
                    // 根據Intent返回時前臺廣播隊列仍是後臺廣播隊列
                    BroadcastQueue queue = broadcastQueueForIntent(intent);
                    // 須要發送的一條廣播記錄,receivers包含了全部能接收該條廣播的接收器
                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                            null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers,
                            null, 0, null, null, false, true, true, -1);
                    // 將該廣播記錄加入廣播隊列中
                    queue.enqueueParallelBroadcastLocked(r);
                    // 調度廣播,發送BROADCAST_INTENT_MSG消息,觸發處理下一個廣播。可是若是目前有廣播還在
                    // 發送的處理過程當中,此次推進不會起做用
                    queue.scheduleBroadcastsLocked();
                }
            }

            return sticky;
        }
    }
複製代碼

上面時註冊廣播的核心代碼,主要是先判斷註冊的廣播的Action是否是已經存在AMS(ActivityManagerService)中的粘性廣播中,若是存在就將這些Intent單獨保存到一個列表中,而後處理廣播接收器,上面代碼和註釋寫的很清楚了,廣播註冊不是直接將receiver保存在AMS中,而是先將其封裝到實現IIntentReceiver接口的Binder對象rd中,而後將這個對象放到ReceiverList對象中,這個ReceiverList對象是一個對應receiver的IntentFilter列表,可是這個列表對象也包含了該receiver對象,也就是將receiver以及其對應的IntentFilter列表封裝到了ReceiverList對象中,這樣每一個廣播接收者以及其Action都封裝好了,而後將其放到該應用所在進程的ReceiverList對象列表中,這樣整個廣播註冊就完成了。ide

其實縷清了這個結構就看懂廣播註冊了:首先是一個進程對象ProcessRecord,裏面有一個廣播的列表ArraySet,這個列表表示改進程註冊的全部廣播接收者,每一個ReceiverList對象包含了一個廣播接收者(實現了IIntentReceiver接口的Binder對象)封裝和與該廣播接收者對應的多個Action對應的IntentFilter對象的封裝BroadcastFilter列表,這個ReceiverList對象是將註冊的廣播接收者以及對應的多個Action對應起來,這樣就能查找對應的廣播接收者,怎麼調用咱們下一篇發送廣播會詳細講解。ui

Step-9:getRecordForAppLocked

final ProcessRecord getRecordForAppLocked( IApplicationThread thread) {
        if (thread == null) {
            return null;
        }

        int appIndex = getLRURecordIndexForAppLocked(thread);
        return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
    }
複製代碼

這裏是根據IApplicationThread獲取是否存在了該進程,這裏調用getLRURecordIndexForAppLocked獲取該進程對應的indexthis

Step-10:getLRURecordIndexForAppLocked

private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
        IBinder threadBinder = thread.asBinder();
        // Find the application record.
        for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
            ProcessRecord rec = mLruProcesses.get(i);
            if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
                return i;
            }
        }
        return -1;
    }
複製代碼

這裏主要經過for循環來從mLruProcesses列表中遍歷是否存在該IApplicationThread,若是存在返回對應的Index,不然返回-1.spa

Step-11:UserController.handleIncomingUser

int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll, int allowMode, String name, String callerPackage) {
        final int callingUserId = UserHandle.getUserId(callingUid);
        if (callingUserId == userId) {
            return userId;
        }

        ...
        int targetUserId = unsafeConvertIncomingUserLocked(userId);

        if (callingUid != 0 && callingUid != SYSTEM_UID) {
            final boolean allow;
            if (mService.checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid,
                    callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
                // If the caller has this permission, they always pass go. And collect $200.
                allow = true;
            }
            ...
            if (!allow) {
                if (userId == UserHandle.USER_CURRENT_OR_SELF) {
                    // In this case, they would like to just execute as their
                    // owner user instead of failing.
                    targetUserId = callingUserId;
                } else {
                    ...
                }
            }
        }
        
        ...
        return targetUserId;
    }
複製代碼

這裏主要獲取callingPid等參數對應的用戶id。

Step-24:BroadcastQueue.scheduleBroadcastsLocked

// 驅動廣播,全部廣播都應該從這裏走,而後會到processNextBroadcast
    public void scheduleBroadcastsLocked() {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

        // mBroadcastsScheduled用來描述AMS是否已經向它所運行在的線程的消息隊列發送了一個類型爲
        // BROADCAST_INTENT_MSG的消息。AMS就是經過這個BROADCAST_INTENT_MSG消息類調度保存在無
        // 序廣播調度隊列mParallelBroadcasts和有序廣播調度隊列mOrderedBroadcasts中的廣播轉發任務的
        if (mBroadcastsScheduled) {// 若是true說明消息隊列已經存在一個類型爲BROADCAST_INTENT_MSG的消息了
            return;
        }
        // 雖然這裏只發送了發送廣播的消息,可是這一步執行完以後就已經標記廣播發送了,所以能夠看出廣播發送和接
        // 受是異步的,即廣播發送者將一個廣播發送給AMS後,不會等待AMS將這個廣播轉發給廣播接收者處理
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }
複製代碼

Broadcast的註銷

瞭解了廣播註冊,廣播註銷就很簡單了,就是從列表中刪除對應的廣播對象封裝。

註銷廣播時序圖

Step-1:unregisterReceiver

public void unregisterReceiver(BroadcastReceiver receiver) {
        if (mPackageInfo != null) {
            IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
                    getOuterContext(), receiver);
            try {
                ActivityManagerNative.getDefault().unregisterReceiver(rd);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } else {
            ...
        }
    }
複製代碼

首先經過LoadedApk.forgetReceiverDispatcher方法獲取與該註銷廣播接收者對應的實現IIntentReceiver接口的Binder對象。

Step-2:LoadedApk.forgetReceiverDispatcher

public IIntentReceiver forgetReceiverDispatcher(Context context, BroadcastReceiver r) {
        synchronized (mReceivers) {
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
            LoadedApk.ReceiverDispatcher rd = null;
            if (map != null) {
                rd = map.get(r);
                if (rd != null) {
                    map.remove(r);
                    if (map.size() == 0) {
                        mReceivers.remove(context);
                    }
                    ...
                    return rd.getIIntentReceiver();
                }
            }
            ...
        }
    }
複製代碼

首先去mReceivers中獲取,咱們從上面註冊知道,註冊時會將實現了IIntentReceiver接口的廣播接收者的封裝放到mReceivers保存,因此這裏先去獲取有沒有,註冊了確定是有的,所以將其移除。

Step-4:ActivityManagerProxy.unregisterReceiver

public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException {
        ...
        mRemote.transact(UNREGISTER_RECEIVER_TRANSACTION, data, reply, 0);
        ...
    }
複製代碼

上面註冊廣播咱們分析過調用ActivityManagerProxy這裏的方法,而後經過Binder傳遞到AMS中對應的方法中

Step-5:ActivityManagerService.unregisterReceiver

// 註銷廣播
    public void unregisterReceiver(IIntentReceiver receiver) {
        ...
        try {
            boolean doTrim = false;

            synchronized (this) {
                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                // 若是不爲null,說明還沒註銷廣播
                if (rl != null) {
                    final BroadcastRecord r = rl.curBroadcast;
                    if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) {
                        final boolean doNext = r.queue.finishReceiverLocked(
                                r, r.resultCode, r.resultData, r.resultExtras,
                                r.resultAbort, false);
                        if (doNext) {
                            doTrim = true;
                            r.queue.processNextBroadcast(false);
                        }
                    }

                    if (rl.app != null) {
                        // 從廣播接收器對應的進程中移除
                        rl.app.receivers.remove(rl);
                    }

                    // 移除對應廣播過濾器
                    removeReceiverLocked(rl);
                    if (rl.linkedToDeath) {
                        rl.linkedToDeath = false;
                        rl.receiver.asBinder().unlinkToDeath(rl, 0);
                    }
                }
            }

            // If we actually concluded any broadcasts, we might now be able
            // to trim the recipients' apps from our working set
            if (doTrim) {
                trimApplications();
                return;
            }

        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
複製代碼

找到對應的註冊廣播對象ReceiverList,而後將其移除。

Step-6:BroadcastQueue.getMatchingOrderedReceiver

public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
        if (mOrderedBroadcasts.size() > 0) {
            final BroadcastRecord r = mOrderedBroadcasts.get(0);
            if (r != null && r.receiver == receiver) {
                return r;
            }
        }
        return null;
    }
複製代碼

從隊列中找到對應的BroadcastRecord對象而後返回。

Step-8:BroadcastQueue.finishReceiverLocked

public boolean finishReceiverLocked(BroadcastRecord r, int resultCode, String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
        final int state = r.state;
        final ActivityInfo receiver = r.curReceiver;
        r.state = BroadcastRecord.IDLE;
        ...
        if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
                && r.queue.mOrderedBroadcasts.size() > 0
                && r.queue.mOrderedBroadcasts.get(0) == r) {
            ActivityInfo nextReceiver;
            if (r.nextReceiver < r.receivers.size()) {
                Object obj = r.receivers.get(r.nextReceiver);
                nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo) obj : null;
            } else {
                nextReceiver = null;
            }
            // Don't do this if the next receive is in the same process as the current one.
            if (receiver == null || nextReceiver == null
                    || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
                    || !receiver.processName.equals(nextReceiver.processName)) {
                if (mService.mServices.hasBackgroundServices(r.userId)) {
                    r.state = BroadcastRecord.WAITING_SERVICES;
                    return false;
                }
            }
        }

        r.curComponent = null;

        // We will process the next receiver right now if this is finishing
        // an app receiver (which is always asynchronous) or after we have
        // come back from calling a receiver.
        return state == BroadcastRecord.APP_RECEIVE
                || state == BroadcastRecord.CALL_DONE_RECEIVE;
    }
複製代碼

這裏判斷是否結束廣播接收,若是結束則處理下一條廣播。

Step-10:BroadcastQueue.processNextBroadcast

這個是處理下一條廣播的,也是廣播的核心部分,這個咱們在下一篇發送廣播時會詳細講解。

Step-11:removeReceiverLocked

void removeReceiverLocked(ReceiverList rl) {
        mRegisteredReceivers.remove(rl.receiver.asBinder());
        for (int i = rl.size() - 1; i >= 0; i--) {
            mReceiverResolver.removeFilter(rl.get(i));
        }
    }
複製代碼

這個就是經過for循環刪除對應的BroadcastFilter對象,這樣就註銷了廣播。

主要的基本都分析了,還有如下其餘不重要的你們想要了解本身看看代碼。

廣播註冊結構

註冊廣播結構圖

最後這裏咱們再加一個廣播註冊結構的總結,上面是一個廣播註冊時的結構圖,也就是廣播以及對應的IntentFilter列表封裝,整個過程是由下向上註冊。首先是將BroadcastReceiver封裝成Binder對象IIntentReceiver,將IntentFilter封裝成BroadcastFilter對象,ReceiverList繼承的是ArrayList<BroadcastFilter>,所以它自己就是一個用來盛放BroadcastFilter對象列表的ArrayList對象,同時ReceiverList對象還放入了IntentFilter列表對應的BroadcastReceiver的封裝對象IIntentReceiver,這樣就將BroadcastReceiver和IntentFilter綁定到一塊兒了,而後將ReceiverList放到mRegisteredReceivers中,保存在ActivityManagerService(AMS)中,同時將ReceiverList放置到該廣播所在進程的receivers中,而該進程保存在AMS中的mLruProcesses中,同時將IntentFilter的封裝對象BroadcastReceiver放置到AMS中的mReceiverResolver中,這樣就註冊完成了。

這樣從整個機構來講就很是清楚了,其實裏面還有一些相互引用的狀況,我沒有徹底畫出來,只畫了主要的部分,相對清晰一些。

Android開發羣:192508518

微信公衆帳號:Code-MX

首發地址:www.codemx.cn

注:本文原創,轉載請註明出處,多謝。

相關文章
相關標籤/搜索