在网站制作完成后网站建设,window部署wordpress,上海做网站优化公司,建设局和住建局该系列文章总纲链接#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 说明#xff1a; 说明#xff1a;本章节主要解读应用层广播组件的发送广播和接收处理广播 2个过程#xff0c;以及从APP层到AMS调用之间的打通。关注思维导图中左上部分即可。
有…该系列文章总纲链接专题总纲目录 Android Framework 总纲 本章关键点总结 说明 说明本章节主要解读应用层广播组件的发送广播和接收处理广播 2个过程以及从APP层到AMS调用之间的打通。关注思维导图中左上部分即可。
有了前面startActivity流程和service组件启动的流程的过程我们基于此继续分析广播组件的发送和接收处理流程过程。
我们先对广播组件的基本概念、分类、以及基本的使用方式有所了解。再基于应用的API入手对关键API进行分析。
1 Android系统中广播的解读
1.1 广播的分类
在Android中广播Broadcast是一种在不同组件之间传递信息的机制。广播可以分为以下几种类型
普通广播Normal Broadcasts异步发送系统会同时将广播发送给所有注册接收该类型广播的接收器。接收器之间没有执行顺序几乎同时接收到广播消息。不能被截断。有序广播Ordered Broadcasts同步发送系统会按照接收器的优先级顺序逐个发送广播。每个接收器都有机会处理广播消息并且可以决定是否继续传递广播。如果接收器决定不再传递广播通过调用abortBroadcast()那么后续的接收器将不会收到该广播。粘性广播Sticky Broadcasts属于标准广播在发送后就一直存在于系统的消息容器里面等待对应的处理器去处理。如果暂时没有处理器处理这个消息则一直在消息容器里面处于等待状态。粘性广播的Receiver如果被销毁那么下次重建时会自动接收到消息数据。系统广播System BroadcastsAndroid内置了很多系统级别的广播我们可以在应用中通过监听这些广播来得到各种系统的状态信息。例如手机开机后会发送一条广播电池的电量发生变化会发出一条广播时间或时区发生改变也会发出一条广播等。App应用内广播Local Broadcast用于应用内部组件之间的通信使用LocalBroadcastManager来管理。相比全局广播应用内广播更高效不需要跨进程通信也不需要考虑安全性问题。
当然随着Android版本发展的迭代一些广播和一些广播发送的方法不再使用参考信息如下
Android 5.0API级别21粘性广播不再支持sendStickyBroadcast 被打上了 Deprecated 标签逐渐被弃用Android 7.0 (API 级别 24) 及更高版本不再发送以下系统广播ACTION_NEW_PICTURE和ACTION_NEW_VIDEOAndroid 8.0 (API 级别 26) 开始对清单声明的接收器施加额外限制如果应用以 Android 8.0 或更高版本为目标平台则不能使用清单来声明接收器对于大多数隐式广播并非针对你的应用。Android 9 (API 级别 28) 开始NETWORK_STATE_CHANGED_ACTION 广播不再接收关于用户所在位置或个人身份信息可识别身份的数据。Android 12 开始ACTION_CLOSE_SYSTEM_DIALOGS 被弃用为了改善用户控制体验在应用程序和系统进行交互时。
这些变更意味着开发者需要根据目标Android版本调整广播的使用以确保应用的兼容性和功能性。
1.2 广播接收器分类
在Android中广播接收器BroadcastReceiver用于接收和处理广播消息。根据广播的类型和用途广播接收器可以分为以下几种
1.2.1 静态注册广播接收器
在AndroidManifest.xml文件中声明系统会在应用启动时自动为这些接收器注册广播。适用于接收系统广播如电池电量变化、屏幕关闭等。当然静态声明接收器也可以接收感兴趣的广播类型参考配置如下
receiverandroid:name.YourBroadcastReceiverandroid:enabledtrueandroid:exportedtrueintent-filteraction android:nameyour.action.YOUR_ACTION //intent-filter
/receiver
这里的your.action.YOUR_ACTION是你自定义的广播动作用于Intent和IntentFilter匹配对应动作。
1.2.2 动态注册广播接收器
一般在代码中通过registerReceiver()方法注册需要在onDestroy()方法中调用unregisterReceiver()来注销。适用于接收应用内部广播或者需要根据应用状态动态注册和注销的广播。在Java代码中动态注册广播接收器代码实现参考如下
IntentFilter filter new IntentFilter();
filter.addAction(your.action.YOUR_ACTION);
registerReceiver(yourBroadcastReceiver, filter);
1.3 发送/接收广播代码实现解读
1.3.1 普通广播
发送普通广播方法如下
// 创建一个Intent包含要发送的动作
Intent intent new Intent(your.action.YOUR_ACTION);
// 可以添加一些额外的数据
intent.putExtra(key, value);// 发送普通广播
sendBroadcast(intent);
接收普通广播
public class NormalReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {// 检查Intent的动作是否是我们期望的if (your.action.YOUR_ACTION.equals(intent.getAction())) {// 处理接收到的数据String value intent.getStringExtra(key);// ...}}
} 在AndroidManifest.xml中静态注册普通广播接收器
receiver android:name.NormalReceiverintent-filteraction android:nameyour.action.YOUR_ACTION //intent-filter
/receiver
或者动态注册
IntentFilter filter new IntentFilter(your.action.YOUR_ACTION);
registerReceiver(new NormalReceiver(), filter);
1.3.2 有序广播
发送有序广播方法如下
// 创建一个Intent包含要发送的动作
Intent intent new Intent(your.action.YOUR_ACTION);
// 可以添加一些额外的数据
intent.putExtra(key, value);// 发送有序广播第二个参数是权限字符串null表示没有权限限制
sendOrderedBroadcast(intent, null);
在发送有序广播时可以通过abortBroadcast()方法来截断广播阻止其继续传递给其他接收器。接收有序广播
public class OrderedReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {// 检查Intent的动作是否是我们期望的if (your.action.YOUR_ACTION.equals(intent.getAction())) {// 处理接收到的数据String value intent.getStringExtra(key);// ...// 如果需要继续传递广播不调用abortBroadcast()否则调用abortBroadcast()来截断广播// abortBroadcast();}}
}
注册普通广播接收器参考1.3.1即可。
请注意有序广播可能会在未来的Android版本中被进一步限制或弃用因为它们可能被滥用来执行恶意行为。因此使用时需要谨慎并考虑应用的目标API级别。
1.3.3 粘性广播Sticky Broadcasts
发送粘性广播
// 创建一个Intent包含要发送的数据
Intent intent new Intent(com.example.myapp.MY_STICKY_BROADCAST);
intent.putExtra(key, value);// 发送粘性广播
sendStickyBroadcast(intent);
接收粘性广播
public class StickyReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {// 处理接收到的数据String value intent.getStringExtra(key);// ...}
}// 在代码中动态注册粘性广播接收器
IntentFilter filter new IntentFilter(com.example.myapp.MY_STICKY_BROADCAST);
registerReceiver(new StickyReceiver(), filter);
注意 如之前描述从Android 5.0API 级别 21开始sendStickyBroadcast 和 sendStickyOrderedBroadcast 方法被标记为不推荐使用因为它们可能会引起安全和隐私问题。建议使用其他方式来传递数据。
1.3.4 系统广播System Broadcasts
关于系统广播的发送我们不需要过渡关心更在于如何接收。
接收系统广播例如电池电量变化
public class SystemReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {int level intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);int scale intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);float batteryPct level / (float) scale;// 处理电池电量变化}}
}// 在AndroidManifest.xml中静态注册系统广播接收器
receiver android:name.SystemReceiverintent-filteraction android:nameandroid.intent.action.BATTERY_CHANGED //intent-filter
/receiver
注册广播接收器参考1.3.1即可。
1.3.5 App应用内广播Local Broadcast
发送应用内广播
// 创建LocalBroadcastManager实例
LocalBroadcastManager localBroadcastManager LocalBroadcastManager.getInstance(context);// 创建一个Intent包含要发送的数据
Intent intent new Intent(com.example.myapp.MY_LOCAL_BROADCAST);
intent.putExtra(key, value);// 发送应用内广播
localBroadcastManager.sendBroadcast(intent);
接收应用内广播
public class LocalReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {// 处理接收到的数据String value intent.getStringExtra(key);// ...}
}// 在代码中动态注册应用内广播接收器
LocalBroadcastManager localBroadcastManager LocalBroadcastManager.getInstance(context);
IntentFilter filter new IntentFilter(com.example.myapp.MY_LOCAL_BROADCAST);
localBroadcastManager.registerReceiver(new LocalReceiver(), filter);
1.4 广播发送和接收案例
以下是一个简单的 Android 应用示例它演示了如何发送和接收普通广播。这个示例包含两个部分一个用于发送广播的 Activity 和一个广播接收器 BroadcastReceiver。
首先你需要在AndroidManifest.xml文件中声明Activity
manifest xmlns:androidhttp://schemas.android.com/apk/res/androidpackagecom.example.dynamicbroadcastdemoapplicationandroid:allowBackuptrueandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcher_roundandroid:supportsRtltrueandroid:themestyle/AppThemeactivity android:name.MainActivityintent-filteraction android:nameandroid.intent.action.MAIN /category android:nameandroid.intent.category.LAUNCHER //intent-filter/activity/application
/manifest
这是一个简单的Activity它将发送一个自定义的广播并动态注册一个广播接收器
package com.example.dynamicbroadcastdemo;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private Button sendBroadcastButton;private MyBroadcastReceiver myBroadcastReceiver;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);sendBroadcastButton findViewById(R.id.sendBroadcastButton);sendBroadcastButton.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {sendBroadcast();}});// 动态注册广播接收器myBroadcastReceiver new MyBroadcastReceiver();IntentFilter filter new IntentFilter();filter.addAction(com.example.dynamicbroadcastdemo.MY_CUSTOM_ACTION);registerReceiver(myBroadcastReceiver, filter);}Overrideprotected void onDestroy() {super.onDestroy();// 注销广播接收器unregisterReceiver(myBroadcastReceiver);}private void sendBroadcast() {Intent intent new Intent(com.example.dynamicbroadcastdemo.MY_CUSTOM_ACTION);// 可以添加额外的数据intent.putExtra(key, value);sendBroadcast(intent);}public class MyBroadcastReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {// 检查Intent的动作是否是我们期望的if (com.example.dynamicbroadcastdemo.MY_CUSTOM_ACTION.equals(intent.getAction())) {// 处理接收到的数据String value intent.getStringExtra(key);Toast.makeText(context, Received broadcast: value, Toast.LENGTH_SHORT).show();}}}
}
编写一个简单的布局文件包含一个按钮用于发送广播
?xml version1.0 encodingutf-8?
RelativeLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentButtonandroid:idid/sendBroadcastButtonandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:textSend Broadcastandroid:layout_centerInParenttrue /
/RelativeLayout
这个示例展示了如何发送和接收一个简单的广播。当用户点击按钮时MainActivity 会发送一个广播MyBroadcastReceiver 接收到广播后会显示一个 Toast 消息。这个示例涵盖了广播的发送和接收的基本流程。
基于此我们对于广播组件的研究起点就从2个关键方法入手
动态注册/注销registerReceiver unregisterReceiver发送普通/有序广播sendBroadcast sendOrderedBroadcast
2 从activity场景到AMS调用的流程
2.1 动态注册/注销流程
2.1.1 从activity.registerReceiver到AMS.registerReceiver
activity.registerReceiver方法是从Context中的registerReceiver开始调用的接口代码实现如下
//Context
Nullable
public abstract Intent registerReceiver(Nullable BroadcastReceiver receiver,IntentFilter filter);Nullable
public abstract Intent registerReceiver(BroadcastReceiver receiver,IntentFilter filter, Nullable String broadcastPermission,Nullable Handler scheduler);
注册时用户的第一个 参数receiver 是继承于 BroadcastReceiver 的。其真正的实现是在ContextImpl中代码实现如下
//ContextImpl//关键流程step1Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {return registerReceiver(receiver, filter, null, null);}//关键流程step2Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,String broadcastPermission, Handler scheduler) {return registerReceiverInternal(receiver, getUserId(),filter, broadcastPermission, scheduler, getOuterContext());}//关键流程step3private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,IntentFilter filter, String broadcastPermission,Handler scheduler, Context context) {// 创建一个IIntentReceiver对象用于与ActivityManagerService通信IIntentReceiver rd null;if (receiver ! null) {if (mPackageInfo ! null context ! null) {if (scheduler null) {// 如果scheduler调度器为null则使用主线程的Handlerscheduler mMainThread.getHandler();}// 创建一个ReceiverDispatcher对象用于调度广播rd mPackageInfo.getReceiverDispatcher(receiver, context, scheduler,mMainThread.getInstrumentation(), true);} else {if (scheduler null) {// 如果scheduler为null则使用主线程的Handlerscheduler mMainThread.getHandler();}// 创建一个LoadedApk.ReceiverDispatcher对象用于调度广播rd new LoadedApk.ReceiverDispatcher(receiver, context, scheduler, null, true).getIIntentReceiver();}}try {// 调用AMS的registerReceiver方法注册广播接收器return ActivityManagerNative.getDefault().registerReceiver(mMainThread.getApplicationThread(), mBasePackageName,rd, filter, broadcastPermission, userId);} catch (RemoteException e) {return null;}}
这里准备一个IIntentReceiver对象调用ActivityManagerNative.getDefault().registerReceiver实际上最终就是调用到AMS的registerReceiver方法中。这一部分参考binder系列文章即可有了或者基础分析起来就较为简单了。系列文章链接为专题分纲目录 android 系统核心机制 binder尤其是这2篇偏实操的
android 系统核心机制binder11binder java层 TestServer分析
android 系统核心机制binder12binder java层 TestClient 分析
2.1.2 从activity.unregisterReceiver到AMS.unregisterReceiver
activity.unregisterReceiver方法是从Context中的unregisterReceiver开始调用的接口代码实现如下
//Context
public abstract void unregisterReceiver(BroadcastReceiver receiver);
其真正的实现是在ContextImpl中代码实现如下
//ContextImplOverridepublic void unregisterReceiver(BroadcastReceiver receiver) {if (mPackageInfo ! null) {IIntentReceiver rd mPackageInfo.forgetReceiverDispatcher(getOuterContext(), receiver);try {ActivityManagerNative.getDefault().unregisterReceiver(rd);} catch (RemoteException e) {}} else {throw new RuntimeException(Not supported in system context);}}
这里直接调用到ActivityManagerNative.getDefault().unregisterReceiver实际上最终就是调用到AMS的unregisterReceiver方法中。其中过程参考2.1节即可。
2.2 发送普通/有序广播流程
2.2.1 从activity.sendBroadcast到AMS.broadcastIntent
activity.sendBroadcast方法是从Context中的sendBroadcast开始调用的接口代码实现如下
//Context
public abstract void sendBroadcast(Intent intent);public abstract void sendBroadcast(Intent intent,Nullable String receiverPermission);public abstract void sendBroadcast(Intent intent,String receiverPermission, int appOp);
其真正的实现是在ContextImpl中代码实现如下
//ContextImplOverridepublic void sendBroadcast(Intent intent) {// 如果这个方法是从系统进程调用的则发出警告。// 说明这是为了限制系统进程滥用发送广播的能力因为这可能会影响到整个系统的稳定性。warnIfCallingFromSystemProcess();// 确定Intent的类型并使用getContentResolver()进行解析。// 说明这一步是为了确保Intent中的数据类型是正确的并且可以被系统正确理解。String resolvedType intent.resolveTypeIfNeeded(getContentResolver());try {// 准备Intent使其可以离开当前进程。// 说明这是为了确保Intent在发送给其他应用或组件时包含所有必要的信息并且是安全的。intent.prepareToLeaveProcess();// 调用AMS的broadcastIntent方法发送广播ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null,Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,getUserId());} catch (RemoteException e) {}}//解读同上内容逻辑基本一致仅传递参数不同Overridepublic void sendBroadcast(Intent intent, String receiverPermission) {warnIfCallingFromSystemProcess();String resolvedType intent.resolveTypeIfNeeded(getContentResolver());try {intent.prepareToLeaveProcess();ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null,Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE,false, false, getUserId());} catch (RemoteException e) {}}//解读同上内容逻辑基本一致仅传递参数不同Overridepublic void sendBroadcast(Intent intent, String receiverPermission, int appOp) {warnIfCallingFromSystemProcess();String resolvedType intent.resolveTypeIfNeeded(getContentResolver());try {intent.prepareToLeaveProcess();ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null,Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false,getUserId());} catch (RemoteException e) {}}
这里直接调用到ActivityManagerNative.getDefault().broadcastIntent实际上最终就是调用到AMS的broadcastIntent方法中。其中过程参考2.1节即可。
2.2.2 从activity.sendOrderedBroadcast到AMS.broadcastIntent
activity.sendOrderedBroadcast方法是从Context中的sendOrderedBroadcast开始调用的接口代码实现如下
//Contextpublic abstract void sendOrderedBroadcast(Intent intent,Nullable String receiverPermission);public abstract void sendOrderedBroadcast(NonNull Intent intent,Nullable String receiverPermission, BroadcastReceiver resultReceiver,Nullable Handler scheduler, int initialCode, Nullable String initialData,Nullable Bundle initialExtras);public abstract void sendOrderedBroadcast(Intent intent,String receiverPermission, int appOp, BroadcastReceiver resultReceiver,Handler scheduler, int initialCode, String initialData,Bundle initialExtras);
其真正的实现是在ContextImpl中代码实现如下
//ContextImpl//解读同sendBroadcast内容逻辑基本一致仅传递参数不同Overridepublic void sendOrderedBroadcast(Intent intent,String receiverPermission) {warnIfCallingFromSystemProcess();String resolvedType intent.resolveTypeIfNeeded(getContentResolver());try {intent.prepareToLeaveProcess();ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null,Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, true, false,getUserId());} catch (RemoteException e) {}}//sendOrderedBroadcast 关键流程step1Overridepublic void sendOrderedBroadcast(Intent intent,String receiverPermission, BroadcastReceiver resultReceiver,Handler scheduler, int initialCode, String initialData,Bundle initialExtras) {sendOrderedBroadcast(intent, receiverPermission, AppOpsManager.OP_NONE,resultReceiver, scheduler, initialCode, initialData, initialExtras);}//sendOrderedBroadcast 关键流程step2Overridepublic void sendOrderedBroadcast(Intent intent,String receiverPermission, int appOp, BroadcastReceiver resultReceiver,Handler scheduler, int initialCode, String initialData,Bundle initialExtras) {warnIfCallingFromSystemProcess();// 初始化IIntentReceiver用于接收广播结果IIntentReceiver rd null;if (resultReceiver ! null) {// 如果提供了resultReceiver则需要创建一个IIntentReceiver对象if (mPackageInfo ! null) {// 如果mPackageInfo不为空使用它来创建ReceiverDispatcherif (scheduler null) {// 如果scheduler为null则使用主线程的Handlerscheduler mMainThread.getHandler();}rd mPackageInfo.getReceiverDispatcher(resultReceiver, getOuterContext(), scheduler,mMainThread.getInstrumentation(), false);} else {// 如果mPackageInfo为空使用LoadedApk来创建ReceiverDispatcherif (scheduler null) {// 如果scheduler为null则使用主线程的Handlerscheduler mMainThread.getHandler();}rd new LoadedApk.ReceiverDispatcher(resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();}}// 解析Intent的类型String resolvedType intent.resolveTypeIfNeeded(getContentResolver());try {intent.prepareToLeaveProcess();// 调用ActivityManagerService的broadcastIntent方法发送有序广播ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, rd,initialCode, initialData, initialExtras, receiverPermission, appOp,true, false, getUserId());} catch (RemoteException e) {}}
这里直接调用到ActivityManagerNative.getDefault().broadcastIntent实际上最终就是调用到AMS的broadcastIntent方法中。其中过程参考2.1节即可。
从这里也可以看到对于有序广播的发送最终和普通广播调用的broadcastIntent方法是一致的。只不过过程中的参数不同。