前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >redis广播模式_广播表

redis广播模式_广播表

作者头像
全栈程序员站长
发布于 2022-10-03 07:52:36
发布于 2022-10-03 07:52:36
1.5K00
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

介绍

BroadcastReceiver 是 Android 的四大组件之一,它作用于应用内、进程间重要的一种通信方式,能够将某个消息通过广播的形式传递给订阅的广播接收器中,下面我们就来分析一下 广播注册到接收到消息 Android 源码到底做了些什么?

源码解析
registerReceiver
时序图
代码讲解

我们跟着上面时序图来讲解代码

先在 MainActivity registerReceiver 广播接收者
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MainActivity extends Activity { 
   
      @Override
    protected void onCreate(Bundle savedInstanceState) { 
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
          //注册广播接收者
                registerReceiver(new ReceiverB(),filterB);
    }
...代码省略...
}

点击 registerReceiver 我们发现并不是 Activity 里面的方法,而是 Activity 的父类 ContextWrapper

ContextWrapper registerReceiver
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback,
AutofillManager.AutofillClient { 

....代码省略...
}
public class ContextThemeWrapper extends ContextWrapper { 

....代码省略...
}
public class ContextWrapper extends Context { 

@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) { 

return mBase.registerReceiver(receiver, filter);
}
}

这里的成员变量 mBase 是 Context,看过 Application 应用启动那块的源码知道 ContextImp 继承了 Context ,那么我们看继承类具体的 registerReceiver 方法吧。

ContextImp registerReceiver
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class ContextImpl extends Context { 
   
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler, int flags) { 

return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext(), flags);
}
}
继续看 registerReceiverInternal
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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) { 

//获取 ActivityThread H 
scheduler = mMainThread.getHandler();
}
//获取 IIntentReceiver 对象,通过它与 AMS 交互,并且通过 Handler 传递消息
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);
if (intent != null) { 

intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) { 

throw e.rethrowFromSystemServer();
}
}

注册广播接收器的函数最终进入到了 ContextImpl 的 registerReceiverInternal 这个函数,这里的成员变量 mPackageInfo 是一个 LoadApk 实例,它是用来负责处理广播的接收。

ActivityThread H

mMainThread.getHandler() 获取的这个 Handler 是用来分发 AMS 发过来的广播。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 private class H extends Handler { 

...
public void handleMessage(Message msg) { 

case RECEIVER:                
handleReceiver((ReceiverData)msg.obj);
maybeSnapshot();
break;
}
....
}
继续看 handleReceiver
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    private void handleReceiver(ReceiverData data) { 

....
//应用 Application 局部变量
Application app;
//广播局部变量
BroadcastReceiver receiver;
//应用 Context
ContextImpl context;
try { 

//制作 Applicaiton
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);
//通过反射进行实例化广播
receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
} catch (Exception e) { 

try { 

if (localLOGV) Slog.v(
sCurrentBroadcastIntent.set(data.intent);
receiver.setPendingResult(data);
//onReceive 进行调用
receiver.onReceive(context.getReceiverRestrictedContext(),
data.intent);
} catch (Exception e) { 

...
} finally { 

sCurrentBroadcastIntent.set(null);
}
....
}
mPackageInfo.getReceiverDispatcher 函数实现
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//LoadeApk
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>();
//以Context 为 key,map 为 values 存储到 mReveivers 中
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else { 

rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}

在 LoadedAPK 类中的 getReceivcerDispatcher 函数中,首先看下 r 是不是已经实例化了,如果没有就创建一个,并且以 r 为 key 值保存在一个 HM 集合中,而这个 map 又被存储在了 mReceivers 中,这样只要给定一个 Activity 和 BroadcastReceiver ,就可以查看 LoadedAPK 里面是否已经存在相应的广播接收发布器了。现在在回到 ContextImpl.registerReceiverInternal 函数,获得了 IIntentReceiver 类型的 Binder 对象后,就开始注册到 AMS 中了,具体代码看下面小点。

AMS registerReceiver
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /** * 这里是通过 Binder 通知调用 * @return Intent */
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;
int callingUid;
int callingPid;
boolean instantApp;
synchronized(this) { 

if (caller != null) { 

//1. 获取进ProcessRecord
callerApp = getRecordForAppLocked(caller);
if (callerApp == null) { 

...代码省略...
}
...代码省略...
//2. 根据 Action 查找匹配的 sticky 接收器
Iterator<String> actions = filter.actionsIterator();
if (actions == null) { 

ArrayList<String> noAction = new ArrayList<String>(1);
noAction.add(null);
actions = noAction.iterator();
}
...代码省略...
//3. 获取 ReceiverList
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 { 

try { 

receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) { 

return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
} else if (rl.uid != callingUid) { 

...代码省略...
}
//4. 构建 BroadcastFilter 对象并且添加到 ReceiverList 中
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
rl.add(bf);
if (!bf.debugCheck()) { 

Slog.w(TAG, "==> For Dynamic broadcast");
}
mReceiverResolver.addFilter(bf);
...代码省略...
return sticky;
}
}
  • 根据上面注释 1 可知,获取进程对应的 pid,uid;
  • 注释 2 获取 IntentFilter 的所有 Action;
  • 注释 3 把广播接收器的 receiver 保存到了一个 ReceiverList 中,这个列表的宿主进程是 rl.app,就是 MainActivity 所在的进程。
  • 注释 4 只是把广播接收器保存起来,但是还没有和 filter 关联起来,这里就创建一个 BroadcastFilter 来把广播接收器列表 rl 和 filter 关联起来,然后保存在 AMS 成员变量 mReceiverResolver 中,这样,就将广播接收器和要接收广播类型的接收器 filter 保存在 AMS 中了,以后就能接到到相应的广播并做处理了。

接下来我们看下 sendBroadcast() 。

onReceive
时序图

在 Activity 通过 sendBroadcast 发送一个广播最后 Binder 发送给 AMS , AMS 根据这个广播的 Action 类型找到相应的广播接收器,然后把这个广播放进自己的消息队列中,完成第一部分广播异步分发。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { 

intent = new Intent(intent);
......代码省略....
if (intent.getComponent() == null) { 

......代码省略....
} else { 

//查询到该 Intent 对应的 BroadcastFilter 也就是接收器列表
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, userId);
}
}
......代码省略....
if (!replaced) { 

queue.enqueueParallelBroadcastLocked(r);
//处理广播分发
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
......代码省略....
return ActivityManager.BROADCAST_SUCCESS;
}

AMS 在消息循环中处理这个广播,并通过 Binder 机制把这个广播分发给注册的 ReceiverDispatch ,ReceiverDispatch 把这个广播放进 MainActivity 所在进程的消息队列中,完成第二部分异步消息分发。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void scheduleBroadcastsLocked() { 

if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) { 

return;
}
//通过 Handler 分发
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: { 

if (DEBUG_BROADCAST) Slog.v(
TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
//处理下一个广播
processNextBroadcast(true);
} break;
....
}
}
}

ReceiverDispatch 的内部类 Args 在 MainActivity 所在的线程消息循环中处理这个广播,最终是将这个广播分发给注册的 Receiver 实例的 onReceiver 处理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final class LoadedApk { 

...
static final class ReceiverDispatcher { 

final class Args extends BroadcastReceiver.PendingResult { 

....
public final Runnable getRunnable() { 

return () -> { 

....
try { 

ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
//回调到接收广播的 onReceiver
receiver.onReceive(mContext, intent);
} catch (Exception e) { 

...
};
}
}
}
...
}
总结

注册跟接收源码分析就到这里差不多了,简单来说广播就是一个订阅 – 发布的过程,通过一些 map 存储 BroadcastReceiver ,key 就是封装了这些广播的信息类,如 Action 之类的,当发布一个广播时通过 AMS 到这个 map 中查询注册了这个广播的 IntentFilter 的 BroadcastReceiver , 然后通过 ReceiverDispatch 将广播分发给各个订阅的对象,从而完成了整个通信过程。 《如何成为一位Android架构师?(架构视频+面试专题文档+学习笔记)》

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/197284.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年9月4日 下,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
android广播注册方式_安卓广播接收器
前面分析了Android系统的广播机制,从本质来说,它是一种消息订阅/发布机制。因此,使用这种消息驱动模型的第一步便是订阅消息;而对Android应用程序来说,订阅消息其实就是注册广播接收器。
全栈程序员站长
2022/10/01
1.1K0
动态注册广播接收器_ip广播系统软件v2.3说明书
从registerReceiver(BroadcastReceiver receiver,IntentFilter filter)出发
全栈程序员站长
2022/10/01
7200
broadcast receiver_consolidator
应用调用RegisterReciever,实质是调用的ContextImpl的registerReceiver,接下来跟一下这个流程:
全栈程序员站长
2022/10/01
4140
broadcast receiver_consolidator
android登录注册跳转的代码_Android开发代码
frameworks/base/core/java/android/content/ContextWrapper.java
全栈程序员站长
2022/10/03
1K0
Android四大组件Broadcast中注册广播registerReceiver流程源代码详解
在Android系统中,为什么需要广播机制呢?广播机制,本质上它就是一种组件间的通信方式,如果是两个组件位于不同的进程当中,那么可以用Binder机制来实现,如果两个组件是在同一个进程中,那么它们之间可以用来通信的方式就更多了,这样看来,广播机制似乎是多余的。然而,广播机制却是不可替代的,它和Binder机制不一样的地方在于,广播的发送者和接收者事先是不需要知道对方的存在的,这样带来的好处便是,系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。在软件工程中,是非常强调模块之间的高内聚低耦合性的,不然的话,随着系统越来越庞大,就会面临着越来越难维护的风险,最后导致整个项目的失败。Android应用程序的组织方式,可以说是把这种高内聚低耦合性的思想贯彻得非常透彻,在任何一个Activity中,都可以使用一个简单的Intent,通过startActivity或者startService,就可以把另外一个Activity或者Service启动起来为它服务,而且它根本上不依赖这个Activity或者Service的实现,只需要知道它的字符串形式的名字即可,而广播机制更绝,它连接收者的名字都不需要知道。
全栈程序员站长
2022/10/01
5940
安卓broadcastreceiver_Android手电筒原理
广播作为四大组件之一,在平时开发过程中会大量使用到,使用方式也是多种多样的,既可以自己在manifest中注册,也可以在java代码中动态注册,既可以接收由系统发出的广播,也可以接受自己定义并发送的广播。广播可以实现进程内以及跨进程之间的通信。从本文开始将分别介绍广播的注册,广播的派发,本地广播(LocalBroadcast)以及Android O上对广播的限制,本文主要介绍广播动态注册。
全栈程序员站长
2022/10/01
3610
安卓broadcastreceiver_Android手电筒原理
笔记:BroadcastReceiver的运行过程
用户1172465
2018/01/08
9430
BroadcastReceiver启动过程
看到啥了?mBase.registerReceiver是一个abstract方法, 具体实现在ContextImpl(Context的具体实现,位置E:\adt\sdk\sources\Android-23\android\app)的registerReceiver中
提莫队长
2019/02/21
7670
Android 四大组件之一:BroadCastReceiver动态注册广播流程
1.在Activity中动态注册广播时,调用registerReceiver方法,会调用到ContextWrapper的registerReceiver方法:
北洋
2021/12/08
1.8K0
Android 四大组件之一:BroadCastReceiver动态注册广播流程
注册机request填什么_注册register
广播的注册分为动态注册和静态注册,静态注册主要在开机后PackageManagerService 利用 AndroidManifest 扫描 安装的apk 获取AndroidManifest内注册的 广播 所以 忽略 静态注册。今天主要介绍 动态广播的注册。
全栈程序员站长
2022/10/01
2.6K0
broadcast 学习
android的广播在应用开发中使用的场景很多,本篇就介绍下广播的基本内容,然后侧重介绍广播的几个关键流程,包含广播的注册,注销,还有广播的发送,本篇侧重的是流程的学习,希望通过学习该流程可以对Android的广播有一个清晰的过程了解,这块知识在分析anr问题的时候很有帮助。
一只小虾米
2022/10/25
4820
Android插件化原理解析——广播的管理
在Activity生命周期管理 以及 插件加载机制 中我们详细讲述了插件化过程中对于Activity组件的处理方式,为了实现Activity的插件化我们付出了相当多的努力;那么Android系统的其他组件,比如BroadcastReceiver,Service还有ContentProvider,它们又该如何处理呢?
weishu
2018/09/05
7850
Android深入四大组件(四)广播的注册、发送和接收过程
前言 我们接着来学习Android四大组件中的BroadcastReceiver,广播主要就是分为注册、接收和发送过程。建议阅读此文前请先阅读Android深入理解四大组件系列的文章,知识重复的部分,本文不再赘述。 1.广播的注册过程 BroadcastReceiver的注册分为两种,分别是静态注册和动态注册,静态注册在应用安装时由PackageManagerService来完成注册过程,关于这一过程,我会在后续的介绍PackageManagerService文章中详细介绍。这里只介绍BroadcastRe
用户1269200
2018/02/01
8630
Android深入四大组件(四)广播的注册、发送和接收过程
四大组件的工作过程
Android系统中的四大组件是构成Android应用程序的基础。包括Activity、Service、BroadcastReceiver、ContentProvider。Android开发中无时无刻不在使用这四大组件。因此了解它们的工作过程能让我们对四大组件的理解更加深刻,同时对Android系统的认识更加清晰。
八归少年
2024/03/12
1500
java lang nullpointer_java.lang.throwable
Intent intent = registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
全栈程序员站长
2022/10/01
4290
从源码角度看广播
几乎每个安卓应用都无可避免的使用到广播。例如监听WIFI的开启状态、时间的获取,甚至是我们最常用的闹钟功能,都是结合着AlarmManager与广播来实现的。理解广播的注册、发送与接收实现源码将使我们更加懂安卓系统,同时,基于对广播的理解,我们也能很快的掌握AMS中其它组件的实现原理。
蜻蜓队长
2018/08/03
5510
从源码角度看广播
一定要用相同的Context 对同一个receiver进行registerReceiver与unregisterReceiver吗?
最近在开发一些功能,突然想到在动态注册和反注册receiver的时候一定要用相同的context吗?我不敢肯定咨询了同事,得到的答案是不行的,然而为了进一步佐证他的观点我自己尝试了一下。也就是查了一下相关代码。
全栈程序员站长
2022/10/01
4880
Android入门教程 | 广播机制 Broadcast
Android应用可以通过广播从系统或其他App接收或发送消息。类似于订阅-发布设计模式。当某些事件发生时,可以发出广播。 系统在某些状态改变时会发出广播,例如开机、充电。App也可发送自定义广播。广播可用于应用间的通讯,是IPC的一种方式。
Android_anzi
2021/10/21
1.8K0
全局事件-广播(Broadcast)
广播是Android SDK的四大组件中唯一需要别动接收数据的组件。也就是说对于Activity、ContentProvider和Service都可以主动调用,并获取返回数据。而负责接收Broadcast数据的接收器却永远不知道什么时候可以接收到广播。从这种表现形式上看,很像面向对象中的事件(Event),对于事件(onClick、onKeydown)来说,从来不会预知用户什么时候触发他们,只能默默的等待不可预知的事件发生。因此,广播也可以被成为全局事件。
小小工匠
2021/08/16
1.1K0
Android 广播机制(Broadcast)介绍与使用
Android应用可以通过广播从系统或其他App接收或发送消息。类似于订阅-发布设计模式。当某些事件发生时,可以发出广播。 系统在某些状态改变时会发出广播,例如开机、充电。App也可发送自定义广播。广播可用于应用间的通讯,是IPC的一种方式。
AnRFDev
2021/02/01
3.2K0
推荐阅读
相关推荐
android广播注册方式_安卓广播接收器
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文