Android广播Broadcast的注册与广播源码过程详解(基于api29)

本文详细讲解了Android广播Broadcast的注册与发送源码流程,包括注册的整体流程概述、源码讲解,以及广播发送的流程。通过对源码的分析,帮助读者理解Broadcast的工作原理,涉及跨进程通信AIDL等技术。文章适合对广播使用有一定了解的开发者阅读,以增强对Broadcast组件的理解。
摘要由CSDN通过智能技术生成

前言

你好!
我是一只修仙的猿,欢迎阅读我的文章。

本篇文章的内容是讲解Broadcast的注册与发送的源码流程,不涉及Broadcast的使用。如果还没了解过广播如何使用的读者可以先去了解一下,但我相信不会的,因为广播在开发是很经常使用的。作为四大组件之一,广播的地位不言而喻。而了解其源码流程,可以更好地帮助我们了解他的工作流程,进而更好地了解Broadcast这个组件。这样在开发中,就会更加有自信去写代码,出现了bug也能更快地定位与解决。

本篇文章涉及大量的代码讲解,因而会显得非常枯燥无味。笔者加了大量的代码注释以及流程图来帮助读者理解。注释是非常重要的,代码外的讲解仅仅只是整体流程的把握,注释才是重点细节。还愿读者可以耐心阅读。

文章我以先把握整体流程,再到细节源码讲解的思路讲解。读者要先对整体流程有个把握,知道整体的方向再去阅读源码,这样不会在源码中丢失了方向,也不会不知道哪个地方是重点。读者亦可以边阅读边查看源码,加深印象。

笔者才疏学浅,有不同观点欢迎评论区或私信讨论。如需转载私信告知即可。
另外欢迎阅读笔者的个人博客一只修仙的猿的个人博客,更精美的UI,拥有更好的阅读体验。

本文大纲:

本文大纲.png

Broadcast注册流程

整体流程概述

broadcast注册整体流程

注册流程相对来说比较简单,这里涉及到两个进程:

  • Activity进程,即注册广播所在进程。
  • AMS进程,AMS即ActivityManagerService,该进程为AMS所在进程。

注册的流程为Activity进程把广播接收器发送给AMS,AMS把广播接收器缓存在内部。流程比较简单。不同的进程当然就涉及到跨进程通信,API29源码使用的是AIDL(Android Interface Define Language),如果不熟悉的读者可以先去了解一下,有帮助对源码的理解。当然我也会在源码讲解中适当做解释,但不会深入讲,因为本文的主题是Broadcast工作流程讲解。

源码讲解

源码流程图

Broadcast注册源码流程.png
  1. 首先直接调用到ContextWrapper的registerReceiver方法,Activity是继承自ContextWrapper的。registerReceiver是Context的抽象方法,ContentWrapper继承自Content,但ContextWrapper本身并没有真正实现了Context的抽象方法,而是使用了装饰者模式。Context的真正实现是他内部的一个变量:mBase。这是ContextImpl的实例,所以最终的真正实现是在ContextImpl中。

    /frameworks/base/core/java/android/content/ContextWrapper.java;
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
         
        // 直接调用mBase的方法。mBase是ContextImpl的实例,也是Context的真正实现。
        return mBase.registerReceiver(receiver, filter);
    }
    

    这里补充一下为什么mBase是ContextImpl的实例。如果你阅读过Activity的启动流程(点击前往Activity的启动流程文章),可以知道是在ActivityThread创建Activity的时候,会给Activity初始化Context。下面看一下这部分的源码:

    /frameworks/base/core/java/android/app/ActivityThread.java
    
    // ActivityThread调用此方法来启动Activity
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
          
       ...
       // 在这里创建了Content,可以看到他的类型是ContentImpl
       ContextImpl appContext = createBaseContextForActivity(r);
       
       ...
       // 在这里把appContext给到了activity。说明这个就是Activity里面的Context的具体实现
       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,
         r.assistToken);
       ...
    }
    
  2. 这一步是ContextImpl的逻辑。主要的任务就是构建IIntentReceiver并请求AMS来注册广播接收器。这里涉及到两个知识点:如何请求AMS,为什么不能直接把BroadcastReceiver传递给AMS。

    第一个问题采用的是跨进程通信技术AIDL(Android Interface Define Language)安卓接口定义语言,主要用于跨进程通信,这里就不详细展开,不然就篇幅过大。读者可自行了解。

    第二个问题,是因为广播涉及跨进程通信,而BoradcastReceiver本身并不支持跨进程,所以要进行封装一下。这个问题会在这一步的源码下面进行补充说明。

    后面的逻辑就交给AMS去处理了。

    /frameworks/base/core/java/android/app/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);
    }
    
    // 此方法主要是获取IIntentReceiver对象
    // 为什么要获取IIntentReceiver上面已经有讲了。
    // 并调用AMS在本地代理对象IActivityManagerService的方法来注册广播接收器
    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context, int flags) {
         
        IIntentReceiver rd = null;
        if (receiver != null) {
         
            // 判断mPackageInfo和context是否为空,选择不同的方式获得IIntentReceiver
            if (mPackageInfo != null && context != null) {
         
                if (scheduler == null) {
         
                    // 注意这里的scheduler是mMainThread.getHandler()
            	    // 他是ActivityThread的内部类H,这里先不管有什么用,注意一下就好,后面会讲到。
                    scheduler = mMainThread.getHandler();
                }
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
            } else {
         
                ...
            }
        }
        try {
         
            // ActivityManager.getService()获取到的对象是AMS在本地的代理对象
            // 通过代理对象可以直接跨进程访问AMS
            // 调用IActivityManagerService的方法来启动
            final Intent intent = ActivityManager.getService().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                    broadcastPermission, userId, flags);
            <
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值