Android四大组件之BroadcastReceiver

来源:互联网 发布:ubuntu下svn服务器搭建 编辑:程序博客网 时间:2024/06/05 02:33

BroadcastReceiver 简介

BroadcastReceiver 广播是一种订阅–通知 事件,广播接收者向Android系统 register (订阅广播),广播发送者向Adnroid系统 sendBroadCast(发送广播),然后Android 系统通知所有注册该广播的接收者,广播接收者收到自己注册的广播之后实现自己想做的事情(该事情一般不超过10s,否则应用会出现ANR)。

BroadCast的分类:

  1. 无序广播:也就是普通广播,只要注册了该action的广播接收者都能收到该广播,且没有先后顺序。

  2. 有序广播:广播接收者按照优先级高低依次接受该广播,并且优先接收的广播可以通过setResultExtras(Bundle)方法,将处理好的结果传送到下一个广播接收者那里。

  3. 粘性广播:发送广播调用的方法 sendStickyBroadcast(Intent),和sendBroadcast(Intent)不同。
    粘性广播会一直保留在内存当中,直到有广播接收者注册该广播,该广播才算结束。不好解释,等会具体看例子。

BroadCase的使用:

一.普通广播:

根据注册方式不同可以分为 静态注册广播和动态注册广播。

1.静态注册广播使用实例

AndroidManifest.xml 如下:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.xjp.mybroadcast">    <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme">        <activity            android:name=".MainActivity"            android:label="@string/app_name">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <!--静态注册广播,此处需要添加广播的action-->        <receiver android:name=".BroadCastReceive1">            <intent-filter>                <action android:name="com.xjp.mybroadcast.BroadCastReceive1"></action>            </intent-filter>        </receiver>    </application></manifest>

2.广播接收者实现如下:

package com.xjp.mybroadcast;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;/** * Description:静态广播接收器 * User: xjp * Date: 2015/5/14 * Time: 14:56 */public class BroadCastReceive1 extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        //TODO 接收到广播之后处理自己的事情        String action = intent.getAction();        String result = intent.getStringExtra("key");        MyLog.d("the BroadCast action is " + action + "   the BroadCast receive result is " + result);    }}

3.广播发送者实现如下:

package com.xjp.mybroadcast;import android.content.Intent;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.View;import android.widget.Button;public class MainActivity extends ActionBarActivity implements View.OnClickListener {    private Button btnSend;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        btnSend = (Button) findViewById(R.id.button);        btnSend.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.button:                sendBraodCast();                break;        }    }    private void sendBraodCast() {        /**         * 申明静态广播的 action 行为         */        String action = "com.xjp.mybroadcast.BroadCastReceive1";        Intent intent = new Intent(action);        intent.putExtra("key", "静态广播测试");        sendBroadcast(intent);    }}

打印结果如下:

4.静态注册广播特点:

  1. 注册广播在 AndroidManifest.xml中。
  2. 广播接收者需重新 继承 BroadcastReceiver 类来实现 onReceive()抽象方法。
  3. 应用退出无需 注销广播,因此导致:即使广播退出之后,如果有其他应用发送该action行为的广播,此应用还是能接收到该广播的,也就是还会打印上面的 结果。

二.动态广播:

import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;import android.support.v4.content.LocalBroadcastManager;import android.support.v7.app.ActionBarActivity;import android.view.View;import android.widget.Button;public class MainActivity extends ActionBarActivity implements View.OnClickListener {    private Button btnSend;    private BroadCastReceive2 myReceive;    private IntentFilter filter;    private final static String ACTION = "com.xjp.mybroadcast.BroadCastReceive2";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        btnSend = (Button) findViewById(R.id.button);        btnSend.setOnClickListener(this);        myReceive = new BroadCastReceive2();        filter = new IntentFilter();        filter.addAction(ACTION);    }    @Override    protected void onResume() {        /**         * 注册广播         */        LocalBroadcastManager.getInstance(this).registerReceiver(myReceive, filter);//官方建议使用//        this.registerReceiver(myReceive, filter);        super.onResume();    }    @Override    protected void onPause() {        /**         * 注销广播         */        LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceive);//官方建议使用//        this.unregisterReceiver(myReceive);        super.onPause();    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.button:                sendBraodCast();                break;        }    }    private void sendBraodCast() {        /**         * 申明广播的 action 行为         */        Intent intent = new Intent(ACTION);        intent.putExtra("key", "动态广播测试");        /**         * 官方提倡使用如下发送广播,原因是更快,更安全,不会导致内存泄漏         */        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);//        this.sendBroadcast(intent);    }    /**     * 内部类实现广播接收器     */    private class BroadCastReceive2 extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            //TODO 接收到广播之后处理自己的事情            String action = intent.getAction();            String result = intent.getStringExtra("key");            MyLog.d("the BroadCast action is " + action + "   the BroadCast receive result is " + result);        }    }}

动态广播特点

  1. 在代码中调用registerReceiver()方法 注册广播。
  2. 广播接收者需重新 继承 BroadcastReceiver 类实现内部类。
  3. 动态广播在应用退出时需要 调用unregisterReceiver()方法来注销广播。如果应用退出时没有注销广播,会报如下错误:这里写图片描述
    因此,我们通常的做法是:在 onResume()中注册广播,在onPause中注销广播。
  4. 当广播注销之后就接收不到任何系统发送的广播了。

三.有序广播:

示例:

<pre name="code" class="java">package com.xjp.mybroadcast;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.View;import android.widget.Button;public class MainActivity extends ActionBarActivity implements View.OnClickListener {    private Button btnSend;    private BroadCastReceive2 myReceive;    private BroadCastReceive3 myReceive3;    private IntentFilter filter;    private IntentFilter filter3;    private final static String ACTION = "com.xjp.mybroadcast.BroadCastReceive2";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        btnSend = (Button) findViewById(R.id.button);        btnSend.setOnClickListener(this);        myReceive = new BroadCastReceive2();        filter = new IntentFilter();        filter.addAction(ACTION);        filter.setPriority(2);//设置广播的优先级, -1000~1000 ,数字越大,优先级越高。        myReceive3 = new BroadCastReceive3();        filter3 = new IntentFilter();        filter3.addAction(ACTION);        filter3.setPriority(1);    }    @Override    protected void onResume() {        /**         * 注册广播         */        registerReceiver(myReceive, filter);        registerReceiver(myReceive3, filter3);        super.onResume();    }    @Override    protected void onPause() {        /**         * 注销广播         */        unregisterReceiver(myReceive);        unregisterReceiver(myReceive3);        super.onPause();    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.button:                sendBraodCast();                break;        }    }    private void sendBraodCast() {        /**         * 申明广播的 action 行为         */        Intent intent = new Intent(ACTION);        intent.putExtra("key", "有序广播测试");        this.sendOrderedBroadcast(intent, null);    }    /**     * 内部类实现广播接收器     */    private class BroadCastReceive2 extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            //TODO 接收到广播之后处理自己的事情            String action = intent.getAction();            String result = intent.getStringExtra("key");            MyLog.d("the BroadCast action is " + action + "   the BroadCast receive result is " + result);            Bundle bundle = new Bundle();            bundle.putString("key", "有序广播处理之后" + "\n" + "再次发送给下一个广播接收者");            intent.putExtra("bundle", bundle);            setResultExtras(bundle);            //切断广播,不再让此广播继续往下发送。            //  abortBroadcast();        }    }    /**     * 内部类实现广播接收器     */    private class BroadCastReceive3 extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            //TODO 接收到广播之后处理自己的事情            String action = intent.getAction();            //要不要接受上一个广播接收器receiver2传来的的数据            Bundle bundle = getResultExtras(true);            MyLog.d("the BroadCast action is " + action + "   the BroadCast receive result is " + bundle.getString("key"));        }    }}

有序广播特点

  1. 所有广播接收者的action是一致的,发送有序广播调用 sendOrderedBroadcast()方法。
  2. 有序广播的接收者需要调用setPriority()方法设置广播接收者的优先级。数字越大,优先接受广播。
  3. 有序广播如果需要终止 广播继续往下发送,可以调用 abortBroadcast()方法切断广播。
  4. 先接收广播者可以将自己的处理结果通过setResultExtras()方法继续传递给下一个广播接收者。
  5. 后接收者可以调用 getResultExtras(true)来自己决定是否接收上一个广播传递过来的数据。

四.粘性广播:

示例 需要在 AndroidManifest.xml中添加 权限:

<uses-permission android:name="android.permission.BROADCAST_STICKY"></uses-permission>  

发送广播的Activity

package com.xjp.mybroadcast;import android.content.Intent;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.View;import android.widget.Button;/** * 发送广播的Activity */public class MainActivity extends ActionBarActivity implements View.OnClickListener {    private Button btnSend;    private final static String ACTION = "com.xjp.mybroadcast.BroadCastReceive1";    private final static String ACTION1 = "com.xjp.mybroadcast.BroadCastReceive2";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        btnSend = (Button) findViewById(R.id.button);        btnSend.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.button:                sendBraodCast();                break;        }    }    private void sendBraodCast() {        /**         * 申明广播的 action 行为         */        Intent intent = new Intent(ACTION);        intent.putExtra("key", "普通广播测试");        sendBroadcast(intent);        Intent intent1 = new Intent(ACTION1);        intent1.putExtra("key", "粘性广播测试");        sendStickyBroadcast(intent1);        startActivity(new Intent(this, RecevieActivity.class));    }}

接受广播的Activity

package com.xjp.mybroadcast;import android.app.Activity;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;/** * Description:接受广播的Activity * User: xjp * Date: 2015/5/14 * Time: 17:03 */public class RecevieActivity extends Activity {    private final static String ACTION1 = "com.xjp.mybroadcast.BroadCastReceive1";    private final static String ACTION2 = "com.xjp.mybroadcast.BroadCastReceive2";    private Receive receive;    private IntentFilter filter1;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        receive = new Receive();        filter1 = new IntentFilter();        filter1.addAction(ACTION1);        filter1.addAction(ACTION2);    }    @Override    protected void onResume() {        super.onResume();        registerReceiver(receive, filter1);    }    @Override    protected void onPause() {        super.onPause();        unregisterReceiver(receive);    }    private class Receive extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            String action = intent.getAction();            String result = intent.getStringExtra("key");            MyLog.d("the BroadCast action is " + action + "   the BroadCast receive result is " + result);        }    }}

打印结果如下:
这里写图片描述
从结果来看,只有粘性广播才能接收到广播信息。

粘性广播特点:

  1. 需要在AndroidManifest.xml中添加权限
    <uses-permission android:name="android.permission.BROADCAST_STICKY"></uses-permission>

  2. 粘性广播发送除了调用方法不同sendStickyBroadcast(intent1),其他都一样。

  3. 一般广播都是先注册广播,才能接收到广播,而粘性广播可以做到先发送广播,哪里需要接收该广播就哪里注册,可以后注册广播拿到广播的结果。这就是 普通广播和粘性广播的区别。从示例中也看出了普通广播在跳转到ReceiveActivity中是接受不到广播发送者发出的广播的,只有粘性广播才能接收到。

有人会奇怪,平时也没看到哪里使用粘性广播??其实我也是看到Android 系统中 监测电池电量部分发现的。贴上代码如下:

// Register for the battery changed eventIntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);/ Intent is sticky so using null as receiver works fine// return value contains the statusIntent batteryStatus = this.registerReceiver(null, filter);// Are we charging / charged?int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING  || status == BatteryManager.BATTERY_STATUS_FULL;boolean isFull = status == BatteryManager.BATTERY_STATUS_FULL;// How are we charging?int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC; 

广播的生命周期:

当广播接收者接收到广播调用完onReceive()方法之后,广播的生命周期就结束了。
因此广播接收器不能执行超过10s耗时任务,也不能在onReceive()方法中创建Thread 来执行耗时任务,你可以开启一个Service来执行后台耗时任务,具体可以参考Android 四大组件之Service 的生命周期和使用。

广播的大概原理:

我们知道,只有先注册了某个广播之后,广播接收者才能收到该广播。广播注册的一个行为是将自己感兴趣的IntentFilter注册到Android系统的AMS(ActivityManagerService)中,里面保存了一个IntentFilter列表。广播发送者将自己的IntentFilter 的action行为发送到AMS中,然后遍历AMS中的IntentFilter列表,看谁订阅了该广播,然后将消息遍历发送到注册了相应IntentFilter的Activity或者Service中—–也就是会调用抽象方法onReceive()方法。其中AMS起到了中间桥梁作用。

系统广播:

Android系统中有很多系统广播,比如:

EventDescriptionIntent.ACTION_AIRPLANE_M关闭或打开飞行模式时的广播Intent.ACTION_BATTERY_CH充电状态,或者电池的电量发生变化;//电池的充电状态、电荷级别改变,不能通过组建声Intent.ACTION_BATTERY_LO表示电池电量低Intent.ACTION_BATTERY_OK表示电池电量充足Intent.ACTION_AIRPLANE_MODE_CHANGED关闭或打开飞行模式时的广播Intent.ACTION_BATTERY_CHANGED充电状态,或者电池的电量发生变化;电池的充电状态、电荷级别改变,不能通过组建声明接收这个广播,只有通过Context.registerReceiver()注册Intent.ACTION_BATTERY_LOW表示电池电量低Intent.ACTION_BATTERY_OKAY表示电池电量充足,即从电池电量低变化到饱满时会发出广播Intent.ACTION_BOOT_COMPLETED在系统启动完成后,这个动作被广播一次(只有一次)。Intent.ACTION_CAMERA_BUTTON按下照相时的拍照按键(硬件按键)时发出的广播Intent.ACTION_CLOSE_SYSTEM_DIALOGS当屏幕超时进行锁屏时,当用户按下电源按钮,长按或短按(不管有没跳出话框),进行锁屏时,android系统都会广播此Action消息Intent.ACTION_CONFIGURATION_CHANGED设备当前设置被改变时发出的广播(包括的改变:界面语言,设备方向,等,请参考Configuration.java)Intent.ACTION_DATE_CHANGED设备日期发生改变时会发出此广播Intent.ACTION_DEVICE_STORAGE_LOW设备内存不足时发出的广播,此广播只能由系统使用,其它APP不可用Intent.ACTION_DEVICE_STORAGE_OK设备内存从不足到充足时发出的广播,此广播只能由系统使用,其它APP不可用Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE移动APP完成之后,发出的广播(移动是指:APP2SD)Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE正在移动APP时,发出的广播(移动是指:APP2SD)Intent.ACTION_GTALK_SERVICE_CONNECTEDGtalk已建立连接时发出的广播Intent.ACTION_GTALK_SERVICE_DISCONNECTEDGtalk已断开连接时发出的广播Intent.ACTION_HEADSET_PLUG在耳机口上插入耳机时发出的广播Intent.ACTION_INPUT_METHOD_CHANGED改变输入法时发出的广播Intent.ACTION_LOCALE_CHANGED设备当前区域设置已更改时发出的广播Intent.ACTION_MANAGE_PACKAGE_STORAGE表示用户和包管理所承认的低内存状态通知应该开始。Intent.ACTION_MEDIA_BAD_REMOVAL未正确移除SD卡(正确移除SD卡的方法:设置–SD卡和设备内存–卸载SD卡),但已把SD卡取出来时发出的广播 ,扩展介质(扩展卡)已经从 SD 卡插槽拔出,但是挂载点 (mount point) 还没解除 (unmount)Intent.ACTION_MEDIA_BUTTON按下”Media Button” 按键时发出的广播,假如有”Media Button” 按键的话(硬件按键)Intent.ACTION_MEDIA_CHECKING插入外部储存装置,比如SD卡时,系统会检验SD卡,此时发出的广播?Intent.ACTION_MEDIA_EJECT已拔掉外部大容量储存设备发出的广播(比如SD卡,或移动硬盘),不管有没有正确卸载都会发出此广播, 用户想要移除扩展介质(拔掉扩展卡)。Intent.ACTION_MEDIA_MOUNTED插入SD卡并且已正确安装(识别)时发出的广播, 扩展介质被插入,而且已经被挂载。Intent.ACTION_MEDIA_NOFS拓展介质存在,但使用不兼容FS(或为空)的路径安装点检查介质包含在Intent.mData领域。Intent.ACTION_MEDIA_REMOVED外部储存设备已被移除,不管有没正确卸载,都会发出此广播, 扩展介质被移除。Intent.ACTION_MEDIA_SCANNER_FINISHED广播:已经扫描完介质的一个目录Intent.ACTION_MEDIA_SCANNER_SCAN_FILE请求媒体扫描仪扫描文件并将其添加到媒体数据库。Intent.ACTION_MEDIA_SCANNER_STARTED;广播:开始扫描介质的一个目录Intent.ACTION_MEDIA_SHARED广播:扩展介质的挂载被解除 (unmount),因为它已经作为 USB 大容量存储被共享。Intent.ACTION_MEDIA_UNMOUNTED广播:扩展介质存在,但是还没有被挂载 (mount)Intent.ACTION_PACKAGE_ADDED成功的安装APK之后//广播:设备上新安装了一个应用程序包。//一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)Intent.ACTION_PACKAGE_CHANGED;一个已存在的应用程序包已经改变,包括包名Intent.ACTION_PACKAGE_DATA_CLEARED清除一个应用程序的数据时发出的广播(在设置--应用管理--选中某个应用,之后点清除数据时?)//用户已经清除一个包的数据,包括包名(清除包程序不能接收到这个广播)Intent.ACTION_PACKAGE_INSTALL触发一个下载并且完成安装时发出的广播,比如在电子市场里下载应用?Intent.ACTION_PACKAGE_REMOVED成功的删除某个APK之后发出的广播, 一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播)Intent.ACTION_PACKAGE_REPLACED替换一个现有的安装包时发出的广播(不管现在安装的APP比之前的新还是旧,都会发出此广播?)Intent.ACTION_PACKAGE_RESTARTED用户重新开始一个包,包的所有进程将被杀死,所有与其联系的运行时间状态应该被移除,包括包名(重新开始包程序不能接收到这个广播)Intent.ACTION_POWER_CONNECTED插上外部电源时发出的广播Intent.ACTION_POWER_DISCONNECTED已断开外部电源连接时发出的广播Intent.ACTION_REBOOT重启设备时的广播Intent.ACTION_SCREEN_OFF屏幕被关闭之后的广播Intent.ACTION_SCREEN_ON屏幕被打开之后的广播Intent.ACTION_SHUTDOWN关闭系统时发出的广播Intent.ACTION_TIMEZONE_CHANGED时区发生改变时发出的广播Intent.ACTION_TIME_CHANGED时间被设置时发出的广播Intent.ACTION_TIME_TICK广播:当前时间已经变化(正常的时间流逝), 当前时间改变,每分钟都发送,不能通过组件声明来接收,只有通过Context.registerReceiver()方法来注册Intent.ACTION_UID_REMOVED一个用户ID已经从系统中移除发出的广播Intent.ACTION_UMS_CONNECTED设备已进入USB大容量储存状态时发出的广播?Intent.ACTION_UMS_DISCONNECTED设备已从USB大容量储存状态转为正常状态时发出的广播?Intent.ACTION_WALLPAPER_CHANGED设备墙纸已改变时发出的广播
0 0