Android 应用可以通过 Android 系统发送或接收广播消息, 其他 Android 应用 发布-订阅 设计模式这些广播会在所关注的事件发生时发送。 例如,Android 系统会在发生各种系统事件时发送广播 例如当系统启动或设备开始充电时。应用 还可以发送自定义广播 自己可能感兴趣的信息(例如,一些新数据 已下载)。
系统优化广播的传递,以便保持 最佳系统运行状况。因此,广播的传送时间 。需要低延迟的进程间通信的应用应 可以考虑使用绑定服务
应用可以注册接收特定的广播。广播发送后 系统会自动向已订阅 接收该特定类型的广播
一般来说,广播可以用作跨应用的消息传递系统 以及常规用户流以外的用户但是,您必须小心避免 让您有机会响应广播并在后台运行作业, 可能会导致系统性能降低
关于系统广播
当各种系统事件发生时,系统会自动发送广播, 例如,当系统进入和退出飞行模式时。系统 系统就会将广播发送到所有订阅接收 事件。
广播消息本身封装在 Intent
中,
对象,其操作字符串用于标识发生的事件(例如,
android.intent.action.AIRPLANE_MODE
)。意图可能还包括
绑定至额外字段的额外信息。例如,飞机
模式 intent 包含一个布尔型 extra,用于指示
模式已开启。
如需详细了解如何读取 intent 以及如何从 请参阅 intent 和 intent 过滤器。
有关系统广播操作的完整列表,请参阅
BROADCAST_ACTIONS.TXT
文件。每个广播操作都有一个
常量字段例如,
“ACTION_AIRPLANE_MODE_CHANGED
”现为
android.intent.action.AIRPLANE_MODE
。每项广播操作的文档
。
系统广播所发生的更改
随着 Android 平台的发展,它会定期改变系统广播的方式 行为。为了支持所有 Android 版本,请谨记以下变更。
Android 14
当应用位于缓存中时
状态,广播传送是
针对系统运行状况进行了优化例如,不太重要的系统广播
ACTION_SCREEN_ON
会在应用处于缓存状态时被延迟。当应用从缓存内容中
进入活动进程
生命周期,系统
任何延迟的广播
声明的重要广播 清单从缓存中暂时移除应用 状态。
Android 9
从 Android 9(API 级别 28)开始,
NETWORK_STATE_CHANGED_ACTION
广播不会接收关于用户所在位置或个人身份的信息
可识别身份的数据
此外,如果您的应用安装在搭载 Android 9 或更高版本的设备上,
来自 Wi-Fi 的系统广播不包含 SSID、BSSID、连接
信息或扫描结果。要获取此信息,请调用
getConnectionInfo()
。
Android 8.0
从 Android 8.0(API 级别 26)开始,系统会强制执行额外 针对清单声明的接收器的限制
如果您的应用以 Android 8.0 或更高版本为目标平台,则不能使用清单 对于大多数隐式广播(并非 )。您仍然可以使用 上下文注册的接收器 。
Android 7.0
Android 7.0(API 级别 24)及更高版本不发送以下系统 广播:
此外,以 Android 7.0 及更高版本为目标平台的应用必须注册 CONNECTIVITY_ACTION
广播
使用 registerReceiver(BroadcastReceiver, IntentFilter)
。
无法在清单中声明接收器。
接收广播
应用可以通过两种方式接收广播:通过清单声明的接收器 和上下文注册的接收器
清单声明的接收器
如果您在清单中声明广播接收器,系统会启动您的 应用(如果应用尚未运行)。
要在清单中声明广播接收器,请执行以下步骤:
指定
<receiver>
元素。<!-- If this receiver listens for broadcasts sent from the system or from other apps, even other apps that you own, set android:exported to "true". --> <receiver android:name=".MyBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="APP_SPECIFIC_BROADCAST" /> </intent-filter> </receiver>
Intent 过滤器指定您的接收器所订阅的广播操作。
创建
BroadcastReceiver
子类并实现onReceive(Context, Intent)
。通过 以下示例中的广播接收器会记录日志并显示内容 以下内容:Kotlin
private const val TAG = "MyBroadcastReceiver" class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { StringBuilder().apply { append("Action: ${intent.action}\n") append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}\n") toString().also { log -> Log.d(TAG, log) val binding = ActivityNameBinding.inflate(layoutInflater) val view = binding.root setContentView(view) Snackbar.make(view, log, Snackbar.LENGTH_LONG).show() } } } }
Java
public class MyBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "MyBroadcastReceiver"; @Override public void onReceive(Context context, Intent intent) { StringBuilder sb = new StringBuilder(); sb.append("Action: " + intent.getAction() + "\n"); sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n"); String log = sb.toString(); Log.d(TAG, log); ActivityNameBinding binding = ActivityNameBinding.inflate(layoutInflater); val view = binding.root; setContentView(view); Snackbar.make(view, log, Snackbar.LENGTH_LONG).show(); } }
如需启用视图绑定,请执行以下操作: 在模块级中 configure viewBinding build.gradle 文件中。
系统软件包管理器会在应用安装时注册接收器。 然后,接收器将成为应用的单独入口点,这意味着 确保系统可以启动应用并传递广播(如果应用未 。
系统会创建一个新的 BroadcastReceiver
组件
对象来处理它接收的每个广播。仅此对象有效
在调用 onReceive(Context, Intent)
期间有效。将代码添加到
返回时,系统会将该组件
活动状态。
上下文注册的接收器
上下文注册的接收器可以接收广播,前提是它们的注册
上下文有效。例如,如果您在一个
Activity
上下文,只要 activity 不被销毁,您就会收到广播。如果您
注册到应用上下文,那么,只要应用
正在运行。
要使用上下文注册接收器,请执行以下步骤:
在应用的模块级 build 文件中,添加 1.9.0 或更高版本的 AndroidX Core 库:
Groovy
dependencies { def core_version = "1.15.0" // Java language implementation implementation "androidx.core:core:$core_version" // Kotlin implementation "androidx.core:core-ktx:$core_version" // To use RoleManagerCompat implementation "androidx.core:core-role:1.0.0" // To use the Animator APIs implementation "androidx.core:core-animation:1.0.0" // To test the Animator APIs androidTestImplementation "androidx.core:core-animation-testing:1.0.0" // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation "androidx.core:core-performance:1.0.0" // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation "androidx.core:core-google-shortcuts:1.1.0" // Optional - to support backwards compatibility of RemoteViews implementation "androidx.core:core-remoteviews:1.1.0" // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation "androidx.core:core-splashscreen:1.2.0-alpha02" }
Kotlin
dependencies { val core_version = "1.15.0" // Java language implementation implementation("androidx.core:core:$core_version") // Kotlin implementation("androidx.core:core-ktx:$core_version") // To use RoleManagerCompat implementation("androidx.core:core-role:1.0.0") // To use the Animator APIs implementation("androidx.core:core-animation:1.0.0") // To test the Animator APIs androidTestImplementation("androidx.core:core-animation-testing:1.0.0") // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation("androidx.core:core-performance:1.0.0") // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation("androidx.core:core-google-shortcuts:1.1.0") // Optional - to support backwards compatibility of RemoteViews implementation("androidx.core:core-remoteviews:1.1.0") // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation("androidx.core:core-splashscreen:1.2.0-alpha02") }
-
Kotlin
val br: BroadcastReceiver = MyBroadcastReceiver()
Java
BroadcastReceiver br = new MyBroadcastReceiver();
创建
IntentFilter
:Kotlin
val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
Java
IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
选择是否应导出广播接收器并向以下对象显示 和设备上的其他应用此接收器是否正在监听已发送的广播 无论是来自系统还是来自其他应用(甚至是您拥有的其他应用),都会使用
RECEIVER_EXPORTED
标志。如果该接收器只监听 广播时,请使用RECEIVER_NOT_EXPORTED
标志。Kotlin
val listenToBroadcastsFromOtherApps = false val receiverFlags = if (listenToBroadcastsFromOtherApps) { ContextCompat.RECEIVER_EXPORTED } else { ContextCompat.RECEIVER_NOT_EXPORTED }
Java
boolean listenToBroadcastsFromOtherApps = false; if (listenToBroadcastsFromOtherApps) { receiverFlags = ContextCompat.RECEIVER_EXPORTED; } else { receiverFlags = ContextCompat.RECEIVER_NOT_EXPORTED; }
通过调用以下方法来注册接收器:
registerReceiver()
:Kotlin
ContextCompat.registerReceiver(context, br, filter, receiverFlags)
Java
ContextCompat.registerReceiver(context, br, filter, receiverFlags);
如需停止接收广播,请调用
unregisterReceiver(android.content.BroadcastReceiver)
。 当您不再需要该接收器时,请务必将其取消注册,或者 上下文不再有效。请注意你注册和取消注册接收器的位置, 例如,如果使用 activity 的上下文在
onCreate(Bundle)
中注册接收器,您将 应该在onDestroy()
中取消注册,以便 防止接收器从 activity 上下文中泄露。如果您注册onResume()
中的接收器,应该 在onPause()
中取消注册,以防止 多次注册该程序(如果您不想接收广播 这样做可以减少不必要的系统开销)。错误做法 在onSaveInstanceState(Bundle)
取消注册, 因为如果用户在历史记录堆栈中后退,则不会调用此方法。
对进程状态的影响
无论是您的BroadcastReceiver
是否正在运行或未影响其包含的进程,这些进程可能会改变其
系统终止的可能性。前台进程执行接收器的 onReceive()
方法。通过
系统除了在极端内存压力下运行进程外,
BroadcastReceiver 会在 onReceive()
后停用。接收方的主机
进程的重要性与其应用组件同等重要。如果该进程
在清单声明的接收器中(用户从未使用
或最近未与之交互),系统可能会在 onReceive()
之后将其终止,以确保
其他更关键的进程可用的资源
因此,广播接收器不应启动长时间运行的后台线程。
在 onReceive()
之后,系统可以随时停止该进程以进行回收
终止已创建的线程。要让进程保持活动状态,请安排
JobService
使用 JobScheduler
从接收器中获取
以便系统知道该进程仍在运行
后台工作概览提供了更多详细信息。
发送广播
Android 为应用提供三种方式来发送广播:
sendOrderedBroadcast(Intent, String)
方法一次向一个接收器发送广播。当每个接收器执行 反过来,就可以将结果传播到下一个接收器,也可以 完全中止广播,这样就不会将其传递给 接收器。您可以使用 匹配 intent-filter 的 android:priority 属性;具有 优先级相同的规则会按任意顺序运行sendBroadcast(Intent)
方法会发送 以未定义的顺序向所有接收器发送广播。这称为常规 广播。这种做法更高效,但也意味着接收器 从其他接收器接收结果,传播从广播接收的数据,或者 中止广播。
以下代码段演示了如何通过创建
intent 并调用 sendBroadcast(Intent)
。
Kotlin
Intent().also { intent -> intent.setAction("com.example.broadcast.MY_NOTIFICATION") intent.putExtra("data", "Nothing to see here, move along.") sendBroadcast(intent) }
Java
Intent intent = new Intent(); intent.setAction("com.example.broadcast.MY_NOTIFICATION"); intent.putExtra("data", "Nothing to see here, move along."); sendBroadcast(intent);
广播消息封装在 Intent
对象中。
intent 的操作字符串必须提供应用的 Java 软件包名称语法和
唯一标识广播事件。您可以将其他信息
使用 putExtra(String, Bundle)
将 intent 传递给 intent。
您还可以通过以下方式将广播限定到同一单位中的一组应用:
对 intent 调用 setPackage(String)
。
通过权限限制广播
利用权限,您可以将广播限定到 特定权限您可以对发件人或 广播接收器。
带权限的发送
当你拨打 sendBroadcast(Intent, String)
或
sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
,您可以指定
权限参数。只有已向以下对象请求该权限的接收方:
Kotlin
sendBroadcast(Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
Java
sendBroadcast(new Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
要接收广播,接收方应用必须通过以下方式请求权限: 如下所示:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
您可以指定现有的系统权限,例如
BLUETOOTH_CONNECT
也可以使用
<permission>
元素。对于
有关权限和安全性的一般信息,请参阅系统
权限。
带权限的接收
如果您在注册广播接收器时指定了权限参数
(使用 registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
或
<receiver>
代码中的
则只有使用
<uses-permission>
标记
(如果该对象为 id 序列,
危险)可向接收器发送 intent。
例如,假设接收方应用有一个清单声明的接收器,如下所示 如下所示:
<receiver android:name=".MyBroadcastReceiver"
android:permission="android.permission.BLUETOOTH_CONNECT">
<intent-filter>
<action android:name="android.intent.action.ACTION_FOUND"/>
</intent-filter>
</receiver>
或者您的接收方应用具有如下所示的上下文注册的接收器:
Kotlin
var filter = IntentFilter(Intent.ACTION_FOUND) registerReceiver(receiver, filter, Manifest.permission.BLUETOOTH_CONNECT, null )
Java
IntentFilter filter = new IntentFilter(Intent.ACTION_FOUND); registerReceiver(receiver, filter, Manifest.permission.BLUETOOTH_CONNECT, null );
然后,为了能够向这些接收器发送广播,发送应用 请求权限,如下所示:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
安全注意事项和最佳做法
下面介绍了一些与发送和接收电子邮件相关的安全注意事项 接收广播:
如果许多应用在 清单,它可能会导致系统启动大量应用,从而导致 对设备性能和用户体验产生重大影响。为避免 因此,请优先使用上下文注册而不是清单声明。 有时,Android 系统本身会强制使用上下文注册的 接收器。例如,传送
CONNECTIVITY_ACTION
广播 上下文注册的接收器。请勿使用隐式 intent 广播敏感信息。通过 注册接收广播的任何应用都可以读取这些信息。 您可以通过以下三种方式控制哪些应用可以接收您的广播:
- 您可以在发送广播时指定权限。
- 在 Android 4.0 及更高版本中,您可以指定
package,其中包含
setPackage(String)
时, 广播。系统会将广播限制到 与软件包匹配。
注册接收器后,任何应用都可能会发送潜在的恶意内容 向应用的接收器发送广播您可以通过多种方式 广播:
- 您可以在注册广播接收器时指定权限。
- 对于清单声明的接收器,您可以将 android:exported 属性设为“false”。接收方未收到 来自应用外部来源的广播。
广播操作的命名空间是全局性的。请确保操作名称 和其他字符串都是在您拥有的命名空间中编写的, 与其他应用发生意外冲突
由于接收器的
onReceive(Context, Intent)
方法在 主线程,它应该快速执行并返回。如果您需要 执行长时间运行的工作,请注意生成线程或启动 因为系统可能会在运行完之后onReceive()
返回。有关详情,请参阅对进程的影响 状态为了执行长时间运行的工作, 建议:- 正在使用以下号码拨打
goAsync()
: 接收器的onReceive()
方法,并将BroadcastReceiver.PendingResult
传递给后台线程。 这样,从onReceive()
返回后,广播将保持活跃状态。 不过,即使采用这种方法,系统仍希望您 (在 10 秒内)。它允许 工作到另一个线程,以免影响主线程。 - 使用
JobScheduler
调度作业。有关 相关信息,请参阅智能作业 时间安排。
- 正在使用以下号码拨打
请勿从广播接收器启动 activity,因为用户体验 非常突兀特别是在有多个接收器的情况下。您可以考虑改为 来显示通知。