BroadcastReceiver工作流程分析

1、动态注册广播接收者

//ContextImpl.java
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用来跨进程通信
        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 {
            //跨进程调用AMS的registerReceiver
            final Intent intent = ActivityManager.getService().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                    broadcastPermission, userId, flags);
           
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

首先获取到IIntentReceiver类型的rd对象,该对象是用来进行跨进程通信的。接着跨进行调用到ActivityManagerService的registerReceiver方法,传入了rd和filter作为参数。BroadcastReceiver实际上是不支持跨进程传输的,我们真正向AMS注册的是rd和filter。而当有广播发送到AMS时候,AMS就是通过广播找到匹配的IIntentReceiver,而IIntentReceiver的本质就是Binder,然后就可以跨进程调用到客户端的IIntentReceiver方法,而IIntentReceiver持有ReceiverDispatcher,ReceiverDispatcher持有BroadcastReceiver,这样就可以调用到BroadcastReceiver的onReceive方法。

接着分析ActivityManagerService的registerReceiver方法

//ActivityManagerService.java
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
        ArrayList<Intent> stickyIntents = null;
        ProcessRecord callerApp = null;
        synchronized(this) {
            if (caller != null) {
                callerApp = getRecordForAppLocked(caller);
            } 

            Iterator<String> actions = filter.actionsIterator();
            //根据action和userId获取到所有的粘性广播
            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);
                        }
                    }
                }
            }
        }

        //收集所有的和filter匹配的粘性广播
        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);
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
                    allSticky.add(intent);
                }
            }
        }

        
        synchronized (this) {
            if (callerApp != null && (callerApp.thread == null
                    || callerApp.thread.asBinder() != caller.asBinder())) {
                // Original caller already died
                return null;
            }
            //把客户端传过来的IIntentReceiver类型的receiver保存到ReceiverList中
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            }
            //把ReceiverList和filter封装到BroadcastFilter中
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            rl.add(bf);
           
            //接着将BroadcastFilter添加到mReceiverResolver中
            //当AMS接收到广播就可以通过mReceiverResolver找到对应的广播接收者
            mReceiverResolver.addFilter(bf);

            //如果AMS中存在粘性广播就可以发送给我们的广播接收者了
            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, AppOpsManager.OP_NONE, null, receivers,
                            null, 0, null, null, false, true, true, -1);
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
            }

            return sticky;
        }
    }

这样AMS的广播接收者动态注册流程就分析完了,接着是广播的发送过程。主要分析普通广播的工作流程。

2、普通广播的发送

//ContextImpl.java
public void sendBroadcast(Intent intent) {
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

跨进程调用到AMS的broadcastIntent方法。

//ActivityManagerService.java
public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean serialized, boolean sticky, int userId) {
        synchronized(this) {
            //验证广播是否合法
            intent = verifyBroadcastLocked(intent);

            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            //调用broadcastIntentLocked
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, bOptions, serialized, sticky,
                    callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }
//ActivityManagerService.java
final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent...boolean ordered...) {
        intent = new Intent(intent);

   		//保存所有静态注册的广播
        List receivers = null;
       //保存所有动态注册的广播
        List<BroadcastFilter> registeredReceivers = null;
        // 如果我们指定了FLAG_RECEIVER_REGISTERED_ONLY这个标志,那么就不会取收集静态注册的广播接收
        //者了,此时广播只会发送给动态注册的接收者
        if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                 == 0) {
            //获取所有静态注册的和intent匹配的广播接收者
            receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
        }
        if (intent.getComponent() == null) {
            ...
            //获取所有动态注册的和intent匹配的广播接收者
            registeredReceivers = mReceiverResolver.queryIntent(intent,
                     resolvedType, false /*defaultOnly*/, userId);
        }
    
    	 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
    	//如果是无序广播,优先将其发送给动态注册的广播接收者
        if (!ordered && NR > 0) {
            
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(intent...registeredReceivers...);
          
            final boolean replaced = replacePending
                    && (queue.replaceParallelBroadcastLocked(r) != null);
         
            if (!replaced) {
                 //将无序广播插入mParallelBroadcasts队列
                queue.enqueueParallelBroadcastLocked(r);
                //将广播发送给对应的广播接收者
                queue.scheduleBroadcastsLocked();
            }
            //对于无序广播来说,已经将其发送给动态注册的广播接收器了,可以将registeredReceivers置空
            registeredReceivers = null;
            NR = 0;
        }
    
    
        int ir = 0;
        if (receivers != null) { 
             // 如果是有序广播,需要将receivers和registeredReceivers合并在一起
            while (it < NT && ir < NR) {
                if (curt == null) {
                    curt = (ResolveInfo)receivers.get(it);
                }
                if (curr == null) {
                    curr = registeredReceivers.get(ir);
                }
                if (curr.getPriority() >= curt.priority) {
                    // Insert this broadcast record into the final list.
                    receivers.add(it, curr);
                    ir++;
                    curr = null;
                    it++;
                    NT++;
                } else {
                    // Skip to the next ResolveInfo in the final list.
                    it++;
                    curt = null;
                }
            }
        }
        while (ir < NR) {
            if (receivers == null) {
                receivers = new ArrayList();
            }
            receivers.add(registeredReceivers.get(ir));
            ir++;
        }


        if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent...);

            final BroadcastRecord oldRecord =
                    replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
            if (oldRecord != null) {
               
            } else {
                queue.enqueueOrderedBroadcastLocked(r); 
                queue.scheduleBroadcastsLocked();
            }
        } 

        return ActivityManager.BROADCAST_SUCCESS;
    }

接着分析queue.scheduleBroadcastsLocked()是如何发送广播的

//BroadcastQueue.java

//执行广播的发送
public void scheduleBroadcastsLocked() {
        if (mBroadcastsScheduled) {
            return;
        }
    	//发送了一条消息
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }
//BroadcastQueue.java
private final class BroadcastHandler extends Handler {
        public BroadcastHandler(Looper looper) {
            super(looper, null, true);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    //这里进行了广播的发送
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    synchronized (mService) {
                        broadcastTimeoutLocked(true);
                    }
                } break;
            }
        }
    }
//BroadcastQueue.java
final void processNextBroadcast(boolean fromMsg) {
        synchronized(mService) {
            BroadcastRecord r;
            if (fromMsg) {
                mBroadcastsScheduled = false;
            }
			//只分析无序广播,其他的就不看了
            // 遍历所有的无序广播
            while (mParallelBroadcasts.size() > 0) {
                r = mParallelBroadcasts.remove(0);
                final int N = r.receivers.size();
                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                   //将无序广播直接发送给对应的广播接收者
                    //前面分析过BroadcastFilter封装了广播接收者相关的信息
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                }
               
            }

        }
    }
//BroadcastQueue.java
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {
        try {
            if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup){
            } else {
                //走到这里
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,new Intent(r.intent),...);
            }
        } catch (RemoteException e) {
          
        }
    }


    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
        
        if (app != null) {
            //广播接收者所在的进程存在并且正在运行
            if (app.thread != null) {
                try {
                    //跨进程调用
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
                } catch (RemoteException ex) {}
            } else {}
        } else {
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }
    }

这里的app.thread指代ApplicationThread,所以会跨进程调用到的广播接收者所在的进程的ApplicationThread的scheduleRegisteredReceiver方法。

public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
                int resultCode, String dataStr, Bundle extras, boolean ordered,
                boolean sticky...) throws RemoteException {
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
        }

这里调用了IIntentReceiver类型的receiver的performReceive方法,InnerReceiver继承自IIntentReceiver.Stub,是Binder通信的服务端,而IIntentReceiver则是Binder通信的客户端,本质就是AIDL。

//LoadedApk.java
LoadedApk.ReceiverDispatcher.InnerReceiver
public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                final LoadedApk.ReceiverDispatcher rd;
                if (intent == null) {
                    rd = null;
                } else {
                    rd = mDispatcher.get();
                }
                
                if (rd != null) {
                    //调用到ReceiverDispatcher的performReceive方法
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } else {
                
                }
            }
        }

//ReceiverDispatcher#performReceive
public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
  			//调用到args.getRunnable()
            if (intent == null || !mActivityThread.post(args.getRunnable())) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManager.getService();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                }
            }
        }

static final class ReceiverDispatcher {
		final IIntentReceiver.Stub mIIntentReceiver;
        final BroadcastReceiver mReceiver;
		final Context mContext;
    	
    	ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                Handler activityThread, Instrumentation instrumentation,
                boolean registered) {

            mIIntentReceiver = new InnerReceiver(this, !registered);
            mReceiver = receiver;
            mContext = context;
        }
    
        final class Args extends BroadcastReceiver.PendingResult {
 			private Intent mCurIntent;
            private final boolean mOrdered;
            public Args(...){
                mCurIntent = intent;
                mOrdered = ordered;
            }
            
            public final Runnable getRunnable() {
                return () -> {
                    final BroadcastReceiver receiver = mReceiver;
                    final boolean ordered = mOrdered;
                    final Intent intent = mCurIntent;
                    try {
                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        receiver.setPendingResult(this);
                        //这里调用了广播接收者的onReceive方法
                        receiver.onReceive(mContext, intent);
                    } 
                };
            }
        }
    }

到这里无序广播的发送和接受就分析完成了。

3、静态注册广播接收者

广播接收者的静态注册由PackageManagerService在启动或者程序安装的时候帮我们完成,只需要我们在AndroidManifest.xml清单文件中注册即可。关于PackageManagerService的我们知识不再本篇的范围。

PackageManagerService的scanPackageLI方法会调用到PackageParser的parsePackage方法,最终会调用到PackageParser的parseBaseApplication

private boolean parseBaseApplication(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError)
        throws XmlPullParserException, IOException {
  		//下面的代码就完成了AndroidManifest.xml中四大组件的解析过程
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            String tagName = parser.getName();
            if (tagName.equals("activity")) {
                Activity a = parseActivity(owner, res, parser, flags, outError, false,
                        owner.baseHardwareAccelerated);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.activities.add(a);

            } else if (tagName.equals("receiver")) {
                //解析广播接收者,这个Activity只是一种数据类型,用来封装receiver的信息。
                //需要注意它和上面的"activity"共有了一个数据类型,给人的感觉有点奇怪
                Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
                //将广播接收者信息添加到Package的receivers列表里
                owner.receivers.add(a);

            } else if (tagName.equals("service")) {
                Service s = parseService(owner, res, parser, flags, outError);
                if (s == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.services.add(s);

            } else if (tagName.equals("provider")) {
                Provider p = parseProvider(owner, res, parser, flags, outError);
                if (p == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.providers.add(p);

            } 
        }


        return true;
    }

 public final static class Package implements Parcelable {
        public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
       //保存了清单文件中的所有广播接收者
        public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
        public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
        public final ArrayList<Service> services = new ArrayList<Service>(0);
 }

到这里广播接收者的静态注册就分析完了。那么广播又是如何发送到静态注册的广播接收者呢?

前面已经分析过当发送广播时,会调用到ActivityManagerService的broadcastIntentLocked方法,其中有段这样的代码:

//ActivityManagerService.java
final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent...) {
        intent = new Intent(intent);
     	//...
        List receivers = null;
        // Need to resolve the intent to interested receivers...
        if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                 == 0) {
            //会去PackageManagerService查询,获取匹配的静态注册的广播信息
            receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
        }
    
    
        if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent...);

            final BroadcastRecord oldRecord =
                    replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
            if (oldRecord != null) {

            } else {
                //然后广播会被添加到mOrderedBroadcasts列表
                queue.enqueueOrderedBroadcastLocked(r);
                //执行广播的发送
                queue.scheduleBroadcastsLocked();
            }
        }
}

接着分析BroadcastQueue的scheduleBroadcastsLocked。

//BroadcastQueue.java
   public void scheduleBroadcastsLocked() {
        if (mBroadcastsScheduled) {
            return;
        }
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }

private final class BroadcastHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    processNextBroadcast(true);
                } break;
            }
        }
    }

最后又进入了BroadcastQueue的processNextBroadcast方法,这里我们只看mOrderedBroadcasts列表相关的逻辑。

//BroadcastQueue.java
final void processNextBroadcast(boolean fromMsg) {
        synchronized(mService) {
            BroadcastRecord r;
            
            do {
                if (mOrderedBroadcasts.size() == 0) {
                    return;
                }
                //拿到队列的第一个元素
                r = mOrderedBroadcasts.get(0);
                ...
            } while (r == null);

            //获取广播接收者的一些包名信息,因为静态注册的接收者我们没有实例化,因为系统会帮助我们实例化
            ResolveInfo info =
                (ResolveInfo)nextReceiver;
            ComponentName component = new ComponentName(
                    info.activityInfo.applicationInfo.packageName,
                    info.activityInfo.name);
			//...
            // 广播接收者所在的进程已经运行
            if (app != null && app.thread != null && !app.killed) {
                try {
                    app.addPackage(info.activityInfo.packageName,
                            info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
                    //会调用到这里,完成广播的发送
                    processCurBroadcastLocked(r, app);
                    return;
                }
            }

            // 如果广播接收者所在进程没启动,需要先启动它
            if ((r.curApp=mService.startProcessLocked(targetProcess,
                    info.activityInfo.applicationInfo,...) {
                ...
                return;
            }
        }
    }

接着分析BroadcastQueue的processCurBroadcastLocked方法

//BroadcastQueue.java
private final void processCurBroadcastLocked(BroadcastRecord r,
            ProcessRecord app) throws RemoteException {
    ...
        try {
     	//最终调用到ApplicationThread的scheduleReceiver方法
        app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver...);
        }
    }
//ActivityThread.java
public final void scheduleReceiver(Intent intent, ActivityInfo info,
                CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
                boolean sync, int sendingUser, int processState) {
            updateProcessState(processState, false);
            ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                    sync, false, mAppThread.asBinder(), sendingUser);
            r.info = info;
            r.compatInfo = compatInfo;
            sendMessage(H.RECEIVER, r);
        }

 private class H extends Handler {
      public void handleMessage(Message msg) {
          case RECEIVER:
                    handleReceiver((ReceiverData)msg.obj);
                    break;
      }
 }

发送了一个H.RECEIVER消息,然后调用了handleReceiver方法,

private void handleReceiver(ReceiverData data) {

        String component = data.intent.getComponent().getClassName();

        BroadcastReceiver receiver;
        try {
            app = packageInfo.makeApplication(false, mInstrumentation);
            context = (ContextImpl) app.getBaseContext();
            if (data.info.splitName != null) {
                context = (ContextImpl) context.createContextForSplit(data.info.splitName);
            }
            java.lang.ClassLoader cl = context.getClassLoader();
            data.intent.setExtrasClassLoader(cl);
            data.intent.prepareToEnterProcess();
            data.setExtrasClassLoader(cl);
            //通过反射创建了BroadcastReceiver对象
            receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
        }

        try {
            receiver.setPendingResult(data);
            //调用BroadcastReceiver的onReceive方法
            receiver.onReceive(context.getReceiverRestrictedContext(),
                    data.intent);
        } 

        if (receiver.getPendingResult() != null) {
            //这个方法会触发下一个广播的处理,一个接着一个。
            data.finish();
        }
    }

这样静态广播的处理流程也分析完了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值