适配面试题

Android 9.0之不同的Context导致广播接收者无法取

2019-09-15  本文已影响0人  android_coder

不同context注册和取消广播引发的问题

1:问题引入

private IntentFilter intentFilter = new IntentFilter();
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
            
        }
    }
};

@Override
protected void onResume() {
    super.onResume();
    intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
    getApplicationContext().registerReceiver(mBroadcastReceiver, intentFilter);
}

@Override
protected void onPause() {
    super.onPause();
    if (mBroadcastReceiver != null) {
        unregisterReceiver(mBroadcastReceiver);
    }
}

上面的逻辑是在一个activity的onResume生命周期中我们用application的context来注册一个关闭,用activity的context来取消注册

2:错误提示

09-05 10:21:28.548 10355 10355 E AndroidRuntime: FATAL EXCEPTION: main
09-05 10:21:28.548 10355 10355 E AndroidRuntime: Process: com.example.test.qkalertdialog, PID: 10355
09-05 10:21:28.548 10355 10355 E AndroidRuntime: java.lang.RuntimeException: Unable to pause activity {com.example.test.qkalertdialog/com.example.test.qkalertdialog.MainActivity}: java.lang.IllegalArgumentException: Receiver not registered: com.example.test.qkalertdialog.MainActivity$7@51af3c4
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.ActivityThread.performPauseActivityIfNeeded(ActivityThread.java:4047)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.ActivityThread.performPauseActivity(ActivityThread.java:4000)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3952)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.servertransaction.PauseActivityItem.execute(PauseActivityItem.java:45)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1819)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:106)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:193)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:6695)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Native Method)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:870)
09-05 10:21:28.548 10355 10355 E AndroidRuntime: Caused by: java.lang.IllegalArgumentException: Receiver not registered: com.example.test.qkalertdialog.MainActivity$7@51af3c4
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.LoadedApk.forgetReceiverDispatcher(LoadedApk.java:1281)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.ContextImpl.unregisterReceiver(ContextImpl.java:1508)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:667)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at com.example.yangyalin_os.qkalertdialog.MainActivity.onPause(MainActivity.java:156)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.Activity.performPause(Activity.java:7345)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1465)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    at android.app.ActivityThread.performPauseActivityIfNeeded(ActivityThread.java:4037)
09-05 10:21:28.548 10355 10355 E AndroidRuntime:    ... 12 more

上面的提示是在onPause中无法取消注册,可以看到这个广播接收者是明明已经注册了,为啥造成上述问题咧

3:Application Context 和Activity Context

我们都知道,applicaiton和activity都是context,但是applicationContext和activity COntext是不是同一个对象呢
我们分析下应用的启动流程

3.1:application和applicaiton context关联的时机

ActivityThread.java

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {
        return mApplication;
    }
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
    Application app = null;
    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }
    try {
        java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                    "initializeJavaContextClassLoader");
            initializeJavaContextClassLoader();
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
        if (!mActivityThread.mInstrumentation.onException(app, e)) {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            throw new RuntimeException(
                "Unable to instantiate application " + appClass
                + ": " + e.toString(), e);
        }
}
mActivityThread.mAllApplications.add(app);
mApplication = app;

ContextImpl.java
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
            null);
    context.setResources(packageInfo.getResources());
    return context;
}
3.2:activity和activity context的关联时机
ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ": " + e.toString(), e);
        }
    }
    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
        if (localLOGV) Slog.v(
                TAG, r + ": app=" + app
                + ", appName=" + app.getPackageName()
                + ", pkg=" + r.packageInfo.getPackageName()
                + ", comp=" + r.intent.getComponent().toShortString()
                + ", dir=" + r.packageInfo.getAppDir());
        if (activity != null) {
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (r.overrideConfig != null) {
                config.updateFrom(r.overrideConfig);
            }
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                    + r.activityInfo.name + " with config " + config);
            Window window = null;
            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                window = r.mPendingRemoveWindow;
                r.mPendingRemoveWindow = null;
                r.mPendingRemoveWindowManager = null;
            }
            appContext.setOuterContext(activity);
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window, r.configCallback);
 .......................................

 private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
    final int displayId;
    try {
        displayId = ActivityManager.getService().getActivityDisplayId(r.token);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }

    ContextImpl appContext = ContextImpl.createActivityContext(
            this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

    final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
    // For debugging purposes, if the activity's package name contains the value of
    // the "debug.use-second-display" system property as a substring, then show
    // its content on a secondary display if there is one.
    String pkgName = SystemProperties.get("debug.second-display.pkg");
    if (pkgName != null && !pkgName.isEmpty()
            && r.packageInfo.mPackageName.contains(pkgName)) {
        for (int id : dm.getDisplayIds()) {
            if (id != Display.DEFAULT_DISPLAY) {
                Display display =
                        dm.getCompatibleDisplay(id, appContext.getResources());
                appContext = (ContextImpl) appContext.createDisplayContext(display);
                break;
            }
        }
    }
    return appContext;
 }
 
static ContextImpl createActivityContext(ActivityThread mainThread,
        LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
        Configuration overrideConfiguration) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");

    String[] splitDirs = packageInfo.getSplitResDirs();
    ClassLoader classLoader = packageInfo.getClassLoader();

    if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies");
        try {
            classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName);
            splitDirs = packageInfo.getSplitPaths(activityInfo.splitName);
        } catch (NameNotFoundException e) {
            // Nothing above us can handle a NameNotFoundException, better crash.
            throw new RuntimeException(e);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
        }
    }

    ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
            activityToken, null, 0, classLoader);

    // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
    displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;

    final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
            ? packageInfo.getCompatibilityInfo()
            : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;

    final ResourcesManager resourcesManager = ResourcesManager.getInstance();

    // Create the base resources for which all configuration contexts for this Activity
    // will be rebased upon.
    context.setResources(resourcesManager.createBaseActivityResources(activityToken,
            packageInfo.getResDir(),
            splitDirs,
            packageInfo.getOverlayDirs(),
            packageInfo.getApplicationInfo().sharedLibraryFiles,
            displayId,
            overrideConfiguration,
            compatInfo,
            classLoader));
    context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
            context.getResources());
    return context;
}          

可以看到applicaiton Context 和Activity context是不同的对象

4:动态广播注册者流程

ContextImpl.java:registerReceiver

public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    return registerReceiver(receiver, filter, null, null);
}
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
        String broadcastPermission, Handler scheduler) {
    return registerReceiverInternal(receiver, getUserId(),
            filter, broadcastPermission, scheduler, getOuterContext(), 0);
}
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
        IntentFilter filter, String broadcastPermission,
        Handler scheduler, Context context, int flags) {
    IIntentReceiver rd = null;
    if (receiver != null) {
        if (mPackageInfo != null && context != null) {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = mPackageInfo.getReceiverDispatcher(
                receiver, context, scheduler,
                mMainThread.getInstrumentation(), true);
        } else {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = new LoadedApk.ReceiverDispatcher(
                    receiver, context, scheduler, null, true).getIIntentReceiver();
        }
    }
    try {
        final Intent intent = ActivityManager.getService().registerReceiver(
                mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                broadcastPermission, userId, flags);
        if (intent != null) {
            intent.setExtrasClassLoader(getClassLoader());
            intent.prepareToEnterProcess();
        }
        return intent;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

我们可以看到这个过程是将receiver转化成ReceiverDispatcher.InnerReceiver的binder对象,然后传到ams那一段,binder通信传递的都是binder对象

rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler,
                mMainThread.getInstrumentation(), true);
....................................................................
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) {
                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);
                }
                map.put(r, rd);
            }
        } else {
            rd.validate(context, handler);
        }
        rd.mForgotten = false;
        return rd.getIIntentReceiver();
    }
}

上面的过程就是从注册列表中查找注册记录,如果之前已经用相同的context注册过,那么就直接取之前注册过的,如果没有那么就重新创建一个
然后放在一个map中存储起来

ActivityManagerService.java::registerReceiver

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
        int flags) {
    enforceNotIsolatedCaller("registerReceiver");
    ArrayList<Intent> stickyIntents = null;
    ProcessRecord callerApp = null;
    final boolean visibleToInstantApps
            = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;---->是否对instant app可见
    int callingUid;
    int callingPid;
    boolean instantApp;
    synchronized(this) {
        if (caller != null) {
            callerApp = getRecordForAppLocked(caller);
            if (callerApp == null) {
                throw new SecurityException(
                        "Unable to find app for caller " + caller
                        + " (pid=" + Binder.getCallingPid()
                        + ") when registering receiver " + receiver);
            }
            if (callerApp.info.uid != SYSTEM_UID &&
                    !callerApp.pkgList.containsKey(callerPackage) &&
                    !"android".equals(callerPackage)) {
                throw new SecurityException("Given caller package " + callerPackage
                        + " is not running in process " + callerApp);
            }
            callingUid = callerApp.info.uid;
            callingPid = callerApp.pid;
        } else {
            callerPackage = null;
            callingUid = Binder.getCallingUid();
            callingPid = Binder.getCallingPid();
        }
        instantApp = isInstantApp(callerApp, callerPackage, callingUid);
        userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                ALLOW_FULL_ONLY, "registerReceiver", callerPackage);---->注册者的userId

        Iterator<String> actions = filter.actionsIterator();------->intent filter中添加的action
        if (actions == null) {------------------------------------->没有添加action
            ArrayList<String> noAction = new ArrayList<String>(1);
            noAction.add(null);
            actions = noAction.iterator();
        }
        // Collect stickies of users
        int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
        while (actions.hasNext()) {
            String action = actions.next();
            for (int id : userIds) {
                ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                if (stickies != null) {
                    ArrayList<Intent> intents = stickies.get(action);
                    if (intents != null) {
                        if (stickyIntents == null) {
                            stickyIntents = new ArrayList<Intent>();
                        }
                        stickyIntents.addAll(intents);
                    }
                }
            }
        }
    }
    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);
            // Don't provided intents that aren't available to instant apps.
            if (instantApp &&
                    (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                continue;
            }
            // If intent has scheme "content", it will need to acccess
            // provider that needs to lock mProviderMap in ActivityThread
            // and also it may need to wait application response, so we
            // cannot lock ActivityManagerService here.
            if (filter.match(resolver, intent, true, TAG) >= 0) {
                if (allSticky == null) {
                    allSticky = new ArrayList<Intent>();
                }
                allSticky.add(intent);
            }
        }
    }
    // The first sticky in the list is returned directly back to the client.
    Intent sticky = allSticky != null ? allSticky.get(0) : null;
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
    if (receiver == null) {
        return sticky;
    }
    synchronized (this) {
        if (callerApp != null && (callerApp.thread == null
                || callerApp.thread.asBinder() != caller.asBinder())) {
            // Original caller already died
            return null;
        }
        ----->根据binder对象从已经注册过的动态注册者列表中查找ReceiverList
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        if (rl == null) {
            rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                    userId, receiver);
            if (rl.app != null) {
                final int totalReceiversForApp = rl.app.receivers.size();
                if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
                    throw new IllegalStateException("Too many receivers, total of "
                            + totalReceiversForApp + ", registered for pid: "
                            + rl.pid + ", callerPackage: " + callerPackage);
                }
                rl.app.receivers.add(rl);
            } else {
                try {
                    receiver.asBinder().linkToDeath(rl, 0);
                } catch (RemoteException e) {
                    return sticky;
                }
                rl.linkedToDeath = true;
            }
            //如果之前没有注册过,那么就放在动态广播注册者列表中去
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        } else if (rl.uid != callingUid) {------------->检查uid是否匹配
            throw new IllegalArgumentException(
                    "Receiver requested to register for uid " + callingUid
                    + " was previously registered for uid " + rl.uid
                    + " callerPackage is " + callerPackage);
        } else if (rl.pid != callingPid) {------------->检查pid
            throw new IllegalArgumentException(
                    "Receiver requested to register for pid " + callingPid
                    + " was previously registered for pid " + rl.pid
                    + " callerPackage is " + callerPackage);
        } else if (rl.userId != userId) {---------------->userid是否匹配
            throw new IllegalArgumentException(
                    "Receiver requested to register for user " + userId
                    + " was previously registered for user " + rl.userId
                    + " callerPackage is " + callerPackage);
        }
        //广播过滤器
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId, instantApp, visibleToInstantApps);
        if (rl.containsFilter(filter)) {
            Slog.w(TAG, "Receiver with filter " + filter
                    + " already registered for pid " + rl.pid
                    + ", callerPackage is " + callerPackage);
        } else {
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadcast");
            }
            mReceiverResolver.addFilter(bf);---------->如果之前没有改intentfilter则添加
        }
        // Enqueue broadcasts for all existing stickies that match
        // this filter.
        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);
                BroadcastQueue queue = broadcastQueueForIntent(intent);
                BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                        null, -1, -1, false, null, null, OP_NONE, null, receivers,
                        null, 0, null, null, false, true, true, -1);
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        }
        return sticky;
    }
}

上面是动态广播的注册流程

5:动态广播接收者的取消流程

动态广播注册有一个好处是:在不需要的时候我们可以取消注册

ContextImpl.java
public void unregisterReceiver(BroadcastReceiver receiver) {
    if (mPackageInfo != null) {
        IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
                getOuterContext(), receiver);
        try {
            ActivityManager.getService().unregisterReceiver(rd);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } else {
        throw new RuntimeException("Not supported in system context");
    }
}
首先mPackgeInfo肯定不为null,因为它表示的是一个加载到内存的apk对象
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);
                }
                if (r.getDebugUnregister()) {
                    ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
                            = mUnregisteredReceivers.get(context);
                    if (holder == null) {
                        holder = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                        mUnregisteredReceivers.put(context, holder);
                    }
                    RuntimeException ex = new IllegalArgumentException(
                            "Originally unregistered here:");
                    ex.fillInStackTrace();
                    rd.setUnregisterLocation(ex);
                    holder.put(r, rd);
                }
                rd.mForgotten = true;
                return rd.getIIntentReceiver();
            }
        }
        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
                = mUnregisteredReceivers.get(context);----->已经取消注册的广播arraymap
        if (holder != null) {-------------->第一次的时候显示是为null的
            rd = holder.get(r);
            if (rd != null) {
                RuntimeException ex = rd.getUnregisterLocation();
                throw new IllegalArgumentException(
                        "Unregistering Receiver " + r
                        + " that was already unregistered", ex);
            }
        }
        if (context == null) {--------------->context不为nul
            throw new IllegalStateException("Unbinding Receiver " + r
                    + " from Context that is no longer in use: " + context);
        } else {
            throw new IllegalArgumentException("Receiver not registered: " + r);
        }

    }
}

private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
= new ArrayMap<>();
mReceivers存储的是广播注册者,其中key是context,所以这里能不能取到数据是跟context相关的,所以不同的context,取消的时候map为null
导致了取不到对应的广播注册者,因此抛出异常throw new IllegalArgumentException("Receiver not registered: " + r);

上一篇下一篇

猜你喜欢

热点阅读