Android总结 - BroadcastReceiver

概述

BroadcastReceiver会接收sendBroadcast()发送的intent。

如果不需要跨进程发送broadcasts,可以考虑使用LocalBroadcastManager (帮助在自己的进程中注册和发送广播),这个类没有跨进程,效率更高并且不需要考虑其他应用所带来的安全问题。

注册Receiver有两种方式:
1. 动态注册,通过Context.registerReceiver() 来注册实例。
2. 静态注册,通过在 AndroidManifest.xml中添加 tag来发发布。

Note: 如果在Activity.onResume() 注册了Receiver, 那么就应该在Activity.onPause()中unregister。不要在 Activity.onSaveInstanceState()中unregister,因为当activity被移到history stack中时,这个回调函数不会被调用。

实例
动态注册:

    @Override
    protected void onResume() {
        super.onResume();

        // onResume 中注册Receiver
        IntentFilter intentFilter = new IntentFilter(ACTION_RECEIVER_DYNAMIC);
        registerReceiver(mReceiver, intentFilter);

    }


    @Override
    protected void onPause() {
        super.onPause();
        // onPause中取消Receiver
        unregisterReceiver(mReceiver);
    }

静态注册:

        <receiver android:name=".app.BroadcastReceiver1$CustomerReceiver1" android:exported="false">
            <intent-filter android:priority="1">
                <action android:name="com.example.android.action.ACTION_RECEIVER_STATIC"/>
            </intent-filter>

        </receiver>

        <receiver android:name=".app.BroadcastReceiver1$CustomerReceiver3" android:exported="false" android:process=":remote">
            <intent-filter android:priority="2">
                <action android:name="com.example.android.action.ACTION_RECEIVER_STATIC"/>
            </intent-filter>
        </receiver>

有两个主要类型的Broadcast可以被接收:

  • 普通广播(通过 Context.sendBroadcast 发送) ,异步。所有的接收这个广播的receivers会在无序中执行,大部分时间是同时执行。这样更高效,同时也意味着,receivers不能使用执行结果以及一些中断的APIs。
  • 有序广播 (通过 Context.sendOrderedBroadcast 发送),一次只能传递到一个 receiver. 每一个 receiver 都会按顺序执行,它会把执行结果传递给下一个receiver,或者完全中断广播那么就不会再传递给其他的receivers。 receivers的执行优先顺序可以通过intent-filter的“android:priority ”属性来设置 ,如果优先级相同那么顺序就是随机的。

sendOrderedBroadcast(Intent intent,
String receiverPermission) ; receiverPermission为null时代表不需要权限。

即使是普通的广播,系统也有可能在一些情况下恢复为一次只传递一个receiver。尤其是那些 receivers 可能需要创建一个进程 ,一次只能跑一个receiver来避免系统重载一个新的进程。但是无论如何,无序的receivers都不能返回结果,也不能终止广播。

Security

BroadcastReceiver可以跨进程的使用,有些东西需要考虑:

  • Intent的命名空间是全局的。确定Intent的action name使用自己的命名空间,否则有可能会和其他应用冲突。
  • 当使用 registerReceiver(BroadcastReceiver, IntentFilter) 时,任何应用都可以给这个receiver发送广播。 可以通过 permissions 来控制谁才能给这个receiver发送广播。
  • 当通过manifest 发布广播并且设置了“ intent-filters ”,那么其他应用可以给它发送广播,不管你指定的filters。为了防止其他的应用给它发送广播,可以把receiver的tag设置为“ android:exported=”false””。
  • 当你使用sendBroadcast(Intent) 或相关方法,其他应用也可以接收这些广播。 可以通过设置“permissions ”来指定谁可以接收。从ICE_CREAM_SANDWICH开始,甚至可以通过设置“Intent.setPackage”来指定给单个应用。

使用LocalBroadcastManager就不会存在上面的问题,因为intent和Broadcast都是在进程内。

permissions可以在发送和接收广播的时候来实施:

  • 在发送的时候, 可以提供一个非空的参数给 sendBroadcast(Intent, String) 或者 sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, Bundle)。只有获取了这个permission 的receivers才能接收这个广播。
  • 在接收的时候,在注册receiver的时候提供一个非空的permission。 要么,调用registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler) 传递一个permission;要么,在AndroidManifest.xml的 tag 中添加permission . 只有获取了相应权限的应用(在AndroidManifest.xml中使用 来请求)可以发送Intent给receiver。

在使用permission之前,首先要在AndroidManifest.xml中申明,如:<permission android:name="android.permission.CUSTOMER_RECEIVER"/>

Receiver Lifecycle

BroadcastReceiver 对象只有在调用onReceive(Context, Intent)时有用,一旦这个方法执行完,那么系统就会任务这个对象需要销毁并且再也不会激活。

在onReceive(Context, Intent) 的实现中有个重要的影响:不允许有异步操作,因为你需要接收异步操作的返回结果,但是这个时候BroadcastReceiver 不在运行状态那么系统可能会杀死它的进程在异步操作完成之前。
尤其是,你不能再BroadcastReceiver中显示一个对话框或者调用bind service。对于前者,你可以使用NotificationManager API来代替;对于后者,你可以使用Context.startService() 去给Service发送命令。

onReceive 是在主线程中执行

Process Lifecycle

当一个进程中有BroadcastReceiver 在执行的时候,这个进程被任务是前台进程并且系统会保持它运行,除非在一些极端情况下。

只要onReceive()执行完了,这个BroadcastReceiver 就不在活动状态了,它所在的进程的重要程度就取决于这个进程中的其他组件。这个特别重要因为加入进程只包含了BroadcastReceiver ,那么当onReceive() 执行完后,系统会认为这个进程为空的,从而为别的更重要的进程而杀掉它。

Receiver标签

    <receiver android:enabled=["true" | "false"]
              android:exported=["true" | "false"]
              android:icon="drawable resource"
              android:label="string resource"
              android:name="string"
              android:permission="string"
              android:process="string" >
        . . .
    </receiver>

属性:

  • android:enabled
    这个属性用于定义系统是否能够实例化这个广播接收器,如果设置为true,则能够实例化,如果设置为false,则不能被实例化。默认值是true。

  • android:exported
    receiver是否可以接收来自别的应用的发出的广播。如果设置true,则能够接收,如果设置为false,则不能够接收。

  • android:icon
    receiver的icon图标。这个属性必须用包含图片定义的可绘制资源来设定。如果没有设置这个属性,会是应用元素的icon属性值来代替。

  • android:label
    这个属性给广播接收器设定一个用户可读的懂的文本标签。如果这个属性没有设置,那么就会使用元素的label属性值来代替。

  • android:name
    这个属性值要用广播接收器的实现类的类名来设置,它是BroadcastReceiver类的一个子类。通常要使用类的全名来设置(如:com.example.project.ReportReceiver)。但是,也可以使用简写(如:.ReportReceiver)。系统会自动的把元素中的package属性所设定的包名添加到这个简写的名称上。

一旦发布了应用程序,就不应该在改变这个名字了(除非android:exported=”false”)。

  • android:permission
    这个属性用于定义把消息发送给该广播接收器的广播器所必须要有的权限。如果没有设置这个属性,那么元素的permission属性所设置的权限就适用于这个广播接收器。如果元素也没有设置权限,那么该接收器就不受权限的保护。

  • android:process
     这个属性用于设置该广播接收器应该运行在那个进程中。通常,应用程序的所有组件都在给应用程序创建的默认进程中运行,它有与应用程序包名相同的名称。元素的process属性能够给它的所有组件设置一个不同的默认进程,但是它的每个组件自己的process属性能够覆盖这个默认设置,这样就允许把一个应用程序分离到多个进程中。
     如果这个属性值用“:”开头,则在需要的时候系统会创建一个新的,应用程序私有的进程,并且该广播接收器也会运行在这个进程中。如果这个属性值用小写字母开头,那么接收器就会运行在以这个属性值命名的全局进程中,它提供使其工作的权限。这样就允许不同的应用程序组件来共享这个进程。

你可能感兴趣的:(android)