Android 浅析 Broadcast (一) 使用

原文链接:https://jasonzhong.github.io/2016/09/18/Android-%E6%B5%85%E6%9E%90-Broadcast-%E4%B8%80-%E4%BD%BF%E7%94%A8/

前言

Linus Benedict Torvalds : RTFSC – Read The Funning Source Code

概括

广播(Broadcast)是在组件之间传播数据(Intent)的一种机制。通过Broadcast发送者和接收者,并且不需要知道对方存在。

使用

Step 1. 创建接收类

创建一个接收类继承BroadcastReceiver类,并覆写onReceive()方法。

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {}
}

Step 2. 注册广播接收器

1.静态注册

<application >
    <receiver 
        android:name=".MyBroadcastReceiver"
        android:exported="true">
        <intent-filter>
            <action android:name="com.unknow.jason.broadcasttest.MY_BROADCAST"/>
        </intent-filter>
    </receiver>
</application>

2.动态注册

intentFilter = new IntentFilter();
intentFilter.addAction("com.unknow.jason.broadcasttest.MY_BROADCAST");

myBroadcastReceiver = new MyBroadcastReceiver();
registerReceiver(myBroadcastReceiver, intentFilter);

unregisterReceiver(myBroadcastReceiver);

Step 3. 发送广播

Intent intent = new Intent("com.unknow.jason.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);

详细使用

静态注册字段

字段 解释
android:banner A Drawable resource providing an extended graphical banner for its associated item. 一个Drawable资源为其相关联的项目提供扩展的图形横幅。
android:description Descriptive text for the associated data. 为关联数据提供描述。
android:directBootAware Indicate if this component is aware of direct boot lifecycle, and can be safely run before the user has entered their credentials (such as a lock pattern or PIN). 指示此组件是否知道直接引导生命周期,并且可以在用户输入其凭据(例如锁定模式或PIN)之前安全运行。
android:enabled Specify whether the receiver is enabled or not (that is, can be instantiated by the system). 指定这个接收者是否被开启。是否被系统注册。
android:exported Flag indicating whether the given application component is available to other applications. 指示给定应用程序组件是否可用于其他应用程序的标志。
android:icon A Drawable resource providing a graphical representation of its associated item. 一个可绘制的资源,提供其关联项目的图形表示。
android:label A user-legible name for the given item. 给定项目的用户可读名称。
android:logo A Drawable resource providing an extended graphical logo for its associated item. 一个Drawable资源,为其相关联的项目提供扩展的图形标志。
android:name Required name of the class implementing the receiver, deriving from BroadcastReceiver. 实现接收器的类的所需名称,源自BroadcastReceiver。
android:permission Specify a permission that a client is required to have in order to use the associated object. 指定客户机必须具有的权限才能使用关联的对象。
android:process Specify a specific process that the associated code is to run in. 指定一个指定的进程让关联的代码在此上运行。
android:roundIcon A Drawable resource providing a graphical representation of its associated item. 一个可绘制的资源,提供其关联项目的图形表示。
android:singleUser If set to true, a single instance of this component will run for all users. 如果设置为true,则此组件的单个实例将为所有用户运行。

LocalBroadcastManager

Helper to register for and send broadcasts of Intents to local objects within your process.帮助程序注册和发送Intents的广播到您的进程中的本地对象。

与使用sendBroadcast(Intent)发送全局广播相比,这具有许多优点:

  1. 您知道您正在播送的数据不会离开您的应用,因此不需要担心泄露私人数据。
  2. 其他应用程序不可能将这些广播发送到您的应用程序,因此您不必担心它们可以利用的安全漏洞。
  3. 它比通过系统发送全局广播更有效。

主要使用方法:

返回值 函数 解释
static LocalBroadcastManager getInstance(Context context)
void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) Register a receive for any local broadcasts that match the given IntentFilter.
boolean sendBroadcast(Intent intent) Broadcast the given intent to all interested BroadcastReceivers.
void sendBroadcastSync(Intent intent) Like sendBroadcast(Intent), but if there are any receivers for the Intent this function will block and immediately dispatch them before returning.
void unregisterReceiver(BroadcastReceiver receiver) Unregister a previously registered BroadcastReceiver.

主要类

BroadcastReceiver

Base class for code that will receive intents sent by sendBroadcast().
翻译:基础类可以接受来自sendBroadcast()发出的intents。

如果你不需要在应用程序发送广播,考虑使用localbroadcastmanager类代替接下来描述的一般工具。这会给你一个更有效的实现(无需跨进程通信),并允许您避免考虑与其他应用程序能够接收或发送广播任何安全问题。

您可以动态地注册这个类用Context.registerReceiver()方法或静态的实例,通过发布在AndroidManifest.xml中的<接收>标记的实现。

注意:如果注册一个接收器在Activity.onResume()函数,你需要反注册在Activity.onPause(). 这将减少不必要的系统开销。不要在Activity.onSaveInstanceState()注册。

有两个主要的类的广播可以用来接收。

  1. 普通广播:(使用 Context.sendBroadcast发出)是完全异步的。所有接收者都运行在一个未定义的顺序里,有时甚至同时接收。这很高效,但也意味着不能使用结束或暂停API。
  2. 有序广播:(使用 Context.sendOrderedBroadcast发出)同一时间只传递一个接收器。每个接收器依次执行,它可以传送结果到下一个接收器,当然也可以暂停传送。这个顺序在android:priority属性里通过 intent-filter定义,如果定义同样的优先级则是随机顺序。

安全性

有这么几点建议:

  1. 这个Intent的命名空间是全局的。
  2. 当你使用registerReceiver(),任何应用程序可以向该注册的接收者发送广播。你可以控制谁可以通过定义的权限发送广播到它。
  3. 当你在应用程序的清单中发布一个接收器并为它指定一个IntentFilter,任何其他应用程序都可以发送到它的广播,不管你指定的筛选器。为了防止别人发送到它,使他们无法使用安卓:android:exported="false"。
  4. 当你使用sendBroadcast(Intent)或者相关方法,一般任何其他应用程序都可以接收这些广播。你可以通过定义的权限控制谁可以接收这些广播。另外,从ice_cream_sandwich,你也可以安全限制广播到单个应用程序利用Intent.setpackage。

接收者的生命周期

一个广播接收者有一个回调方法:void onReceive()。当一个广播消息到达接收者时,Android调用它的onReceive()方法并传递给它包含消息的Intent对象。广播接收者被认为仅当它执行这个方法时是活跃的。当onReceive()返回后,它是不活跃的。有一个活跃的广播接收者的进程是受保护的,不会被杀死。但是系统可以在任何时候杀死仅有不活跃组件的进程,当占用的内存别的进程需要时。
特别是,你可能不会显示一个对话框或绑定到一个服务在一个BroadcastReceiver中。对于前者,你应该使用NotificationManager API。对于后者,你可以使用上下文:startservice()将命令发送到服务。

进程的生命周期

一个进程,目前正在执行一个BroadcastReceiver(即目前在运行onReceive代码(Context,Intent)函数)被认为是一个前台进程将保持运行的系统除了在极端的内存压力下。
这意味着如果想保持进程长时间运行可以经常利用一个服务去调用BroadcastReceiver来保持进程不被删除

onReceive()

这个方法是当BroadcastReceiver收到一个Intent broadcast消息是被调用。该方法是在其进程的主线程调用的,除非明确地要求运行在不同的线程利用registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler)这个函数。不允许在主线程做耗时的任务,因此也不要onreceive()推出弹出对话框。
如果这个BroadcastReceiver通过<receiver>标签发送,当这个函数返回后这个对象将不在存在。这意味着你不应该进行任何操作在返回结果后特别是异步,对正在互动的服务,应该用startService(Intent)代替bindService(Intent, ServiceConnection, int)。如果你希望和正在运行的服务互动,应该调用peekService(Context, Intent)。
被用在registerReceiver(BroadcastReceiver, IntentFilter) 和application manifests的IntentFilter不保证独有。onReceive()实现应该只对已知的action作出反应,忽略那些未知的被收到的Intent。

推荐阅读更多精彩内容