Android核心基础-9.Android四大组件之BroadcastReceiver

来源:互联网 发布:淘宝客拉人广告词 编辑:程序博客网 时间:2024/06/06 04:20

9.BroadcastReceiver

9.1.什么是BroadcastReceiver

  • 安卓四大组件之一, 用来接收广播, 当收到广播的时候, 可以执行一段代码.
  • 安卓手机在一些事件发生的时候会发出广播, 例如: 开机, 收到短信, 呼出电话, 网络切换, 电量低…
  • 我们定义一个广播接收者, 就可以接收这些广播, 在事件发生的时候, 做一些事情.
  • 我们也可以自己调用API发送广播, 通知其他接收者做一些事情.

9.2.如何收广播, 创建BroadcastReciever

  • 定义类继承BroadcastReceiver, 实现onReceive()方法
  • 清单文件注册<receiver>标签, 用<intent-filter><action>声明接收哪一类广播
  • 当收到广播的时候, 就会自动执行onReceive()方法

创建

public class SmsReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) { // 收到广播时自动执行        System.out.println("收到广播啦");    }}

清单文件

<receiver android:name="net.dxs.broadcastreceiver.SmsReceiver" >    <intent-filter android:priority="2147483647" >        <!-- 接收短信广播 -->        <action android:name="android.provider.Telephony.SMS_RECEIVED" />    </intent-filter></receiver>

注意: 从安卓3.1版本之后, 广播默认不会启动一个安装到手机上却从未启动过的应用. 发广播时希望包含未启动的应用要设置intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);

示例源码->百度网盘

9.3.如何发广播

  • a.普通广播:
    • 接收者之间不能传递数据, 不能中断
    • 创建Intent, 指定Action, 使用sendBroadcast()发送广播
  • b.有序广播
    • 接收者之间可以传递数据, 可以中断
    • 创建Intent, 指定Action, 使用sendOrderedBroadcast()发送广播

发送普通广播

public void sendNormal(View v) {    Intent intent = new Intent("dxs.broadcast.NORMAL");    intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); // 包含从未启动过的应用(3.1之后默认不包含)    intent.putExtra("data", "普通广播Intent发送的数据");    sendBroadcast(intent, null);}

发送有序广播

public void sendOrdered(View v) {    Intent intent = new Intent("dxs.broadcast.ORDERED");    intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);    intent.putExtra("data", "有序广播Intent发送的数据");    Bundle bundle = new Bundle();    bundle.putString("name", "张三");    bundle.putInt("age", 21);    sendOrderedBroadcast(intent, "dxs.permission.BROADCAST", new ResultReceiver(), null, 1, "MainActivity", bundle);}

示例源码->百度网盘
示例源码->百度网盘
示例源码->百度网盘

普通广播和有序广播接收顺序指定
- 接收者的顺序通过<intent-filter android:priority="2">指定, 越大越先收到
- 优先级的取值范围: -2147483648 至 2147483647

9.4.发广播时传递数据

  • a.使用Intent传递数据
    • 无论普通广播, 还是有序广播, 都可以使用Intent给所有的接收者传递数据
    • 该数据在多个接收者之间不能修改
  • b.使用ResultAPI
    • 有序广播可以使用ResultAPI传递数据
    • 其他接收者收到这些数据后是可以修改的

9.5.ResultReceiver

  • sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)方法的第三个参数可以传递一个BroadcastReceiver
  • 这个接收者不用在清单中注册, 它会在最后一个收到广播
  • 可以用他来检测广播传递的数据最后被修改成什么样了

9.6.中断广播

  • 有序广播可以使用abortBroadcast()中断, 阻止后面的接收者接收广播(ResultReceiver除外)

9.7.广播的权限

  • a.发送端要求接收端的权限
    • 在发送广播的时候, 第二个参数可以传入一个权限, 接收端必须持有该权限才能接收广播(ResultReceiver除外)
  • b.接收端要求发送端的权限
    • 接收端在<receiver>标签的android:permission属性中可以指定发送端必须持有某个权限, 如果发送端没有权限, 接收端将不接收广播

9.8.代码注册临时的BroadcastReceiver

  • 使用清单文件注册的广播接收者在手机上永久有效(除非卸载)
  • registerReceiver()可以注册一个临时的广播接收者
  • unregisterReceiver()可以把临时的接收者注销

示例源码->百度网盘

9.9.BroadcastReceiver中耗时操作的问题

  • BroadcastReceive是在主线程中执行的, 不能执行一些耗时的操作
  • 广播接收者的生命周期从收到广播的时候开始, 到onReceive()方法执行结束后结束. 进程中如果没有其他组件, 容易被杀死.
  • 如果在新线程中做耗时的操作, 由于进程会被杀, 操作可能就不能执行完毕.

9.10.Activity中耗时操作的问题

  • Activity也是主线程中执行代码, 同样不能执行耗时的操作
  • Activity退出后进程中如果没有其他组件, 就成为了空的进程, 非常容易被杀死.
  • Activity在后台的时候, 如果进程中没有其他组件, 也有可能被杀死.
  • 如果在新线程中做耗时的操作, 由于进程会被杀, 操作可能就不能执行完毕.

9.11.短信黑名单

  • 定义广播接收者接收android.provider.Telephony.SMS_RECEIVED, 需要android.permission.RECEIVE_SMS权限
  • 收到广播后获取短信数据”pdus”, 封装成SmsMessage对象, 过滤数据
  • 如果遇到敏感数据, abortBroadcast()
public class SmsReceiver extends BroadcastReceiver {    // 系统收到短信 -> 发出广播 -> 自定义接收者 -> 过滤数据(中断) -> 短信应用(广播接收者) -> 通知    @Override    public void onReceive(Context context, Intent intent) { // 收到广播时自动执行        System.out.println("onReceive");        Object[] pdus = (Object[]) intent.getExtras().get("pdus");        for (Object pdu : pdus) {            SmsMessage sms = SmsMessage.createFromPdu((byte[]) pdu); // 把pdu封装成SmsMessage对象            Date date = new Date(sms.getTimestampMillis());            String num = sms.getOriginatingAddress();            String body = sms.getMessageBody();            System.out.println(date + ": " + num + ": " + body);            if ("18600012345".equals(num))                abortBroadcast();        }    }}

示例源码->百度网盘

9.12.自动IP拨号

  • 在呼出电话的时候, 系统会发出一个广播
  • 我们定义接收者, 接收这个广播, 改变其中的电话号码
    • 下一个接收者(系统的呼叫功能), 呼叫的号码就是我们修改后的号码了
public class IPReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        String number = getResultData();        if (!number.startsWith("17951"))            setResultData("17951" + number);        //      setResultData("");    }}

附录广播的一些权限

BATTERY_CHANGED_ACTION                  充电状态,或者电池的电量发生变化 "android.intent.action.BATTERY_CHANGED"BOOT_COMPLETED_ACTION                   在系统启动后,这个动作被广播一次(只有一次) "android.intent.action.BOOT_COMPLETED"CALL_FORWARDING_STATE_CHANGED_ACTION    语音电话的呼叫转移状态已经改变 "android.intent.action.CFF"CONFIGURATION_CHANGED_ACTION            设备的配置信息已经改变,参见 Resources.Configuration. "android.intent.action.CONFIGURATION_CHANGED" Creator CREATOR 无 无DATA_ACTIVITY_STATE_CHANGED_ACTION      电话的数据活动(data activity)状态(即收发数据的状态)已经改变。"android.intent.action.DATA_ACTIVITY"DATA_CONNECTION_STATE_CHANGED_ACTION    电话的数据连接状态已经改变 "android.intent.action.DATA_STATE"DATE_CHANGED_ACTION                     日期被改变 "android.intent.action.DATE_CHANGED"FOTA_CANCEL_ACTION                      取消所有被挂起的 (pending) 更新下载 "android.server.checkin.FOTA_CANCEL"FOTA_INSTALL_ACTION                     更新已经被确认,马上就要开始安装 "android.server.checkin.FOTA_INSTALL"FOTA_READY_ACTION                       更新已经被下载,可以开始安装 "android.server.checkin.FOTA_READY"FOTA_RESTART_ACTION                     恢复已经停止的更新下载 "android.server.checkin.FOTA_RESTART"FOTA_UPDATE_ACTION                      通过 OTA 下载并安装操作系统更新 "android.server.checkin.FOTA_UPDATE"MEDIABUTTON_ACTION                      用户按下了“Media Button” "android.intent.action.MEDIABUTTON"MEDIA_BAD_REMOVAL_ACTION                扩展介质(扩展卡)已经从 SD 卡插槽拔出,但是挂载点 (mount point) 还没解除 (unmount) "android.intent.action.MEDIA_BAD_REMOVAL"MEDIA_EJECT_ACTION                      用户想要移除扩展介质(拔掉扩展卡) "android.intent.action.MEDIA_EJECT"MEDIA_MOUNTED_ACTION                    扩展介质被插入,而且已经被挂载 "android.intent.action.MEDIA_MOUNTED"MEDIA_REMOVED_ACTION                    扩展介质被移除。 "android.intent.action.MEDIA_REMOVED"MEDIA_SCANNER_FINISHED_ACTION           已经扫描完介质的一个目录 "android.intent.action.MEDIA_SCANNER_FINISHED"MEDIA_SCANNER_STARTED_ACTION            开始扫描介质的一个目录 "android.intent.action.MEDIA_SCANNER_STARTED"MEDIA_SHARED_ACTION                     扩展介质的挂载被解除 (unmount),因为它已经作为 USB 大容量存储被共享 "android.intent.action.MEDIA_SHARED"MEDIA_UNMOUNTED_ACTION                  扩展介质存在,但是还没有被挂载 (mount) "android.intent.action.MEDIA_UNMOUNTED"MESSAGE_WAITING_STATE_CHANGED_ACTION    电话的消息等待(语音邮件)状态已经改变 "android.intent.action.MWI"TIMEZONE_CHANGED_ACTION                 时区已经改变 "android.intent.action.TIMEZONE_CHANGED"TIME_CHANGED_ACTION                     时间已经改变(重新设置) "android.intent.action.TIME_SET"TIME_TICK_ACTION                        当前时间已经变化(正常的时间流逝) "android.intent.action.TIME_TICK"UMS_CONNECTED_ACTION                    设备进入 USB 大容量存储模式 "android.intent.action.UMS_CONNECTED"UMS_DISCONNECTED_ACTION                 设备从 USB 大容量存储模式退出 "android.intent.action.UMS_DISCONNECTED"WALLPAPER_CHANGED_ACTION                系统的墙纸已经改变 "android.intent.action.WALLPAPER_CHANGED"XMPP_CONNECTED_ACTION                   XMPP 连接已经被建立 "android.intent.action.XMPP_CONNECTED"XMPP_DISCONNECTED_ACTION                XMPP 连接已经被断开 "android.intent.action.XMPP_DINETWORK_TICKLE_RECEIVED_ACTION          设备收到了新的网络 "tickle" 通知 "android.intent.action.NETWORK_TICKLE_RECEIVED"PACKAGE_ADDED_ACTION                    设备上新安装了一个应用程序包 "android.intent.action.PACKAGE_ADDED"PACKAGE_REMOVED_ACTION                  设备上删除了一个应用程序包 "android.intent.action.PACKAGE_REMOVED"PHONE_STATE_CHANGED_ACTION              电话状态已经改变 "android.intent.action.PHONE_STATE"PROVIDER_CHANGED_ACTION                 更新将要(真正)被安装 "android.intent.action.PROVIDER_CHANGED"PROVISIONING_CHECK_ACTION               要求 polling of provisioning service 下载最新的设置 "android.intent.action.PROVISIONING_CHECK"SCREEN_OFF_ACTION                       屏幕被关闭 "android.intent.action.SCREEN_OFF"SCREEN_ON_ACTION                        屏幕已经被打开 "android.intent.action.SCREEN_ON"SERVICE_STATE_CHANGED_ACTION            电话服务的状态已经改变 "android.intent.action.SERVICE_STATE"SIGNAL_STRENGTH_CHANGED_ACTION          电话的信号强度已经改变 "android.intent.action.SIG_STR"STATISTICS_REPORT_ACTION                要求 receivers 报告自己的统计信息 "android.intent.action.STATISTICS_REPORT"STATISTICS_STATE_CHANGED_ACTION         统计信息服务的状态已经改变 "android.intent.action.STATISTICS_STATE_CHANGED"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_DOCK_EVENT;////发出此广播的地方frameworks\base\services\java\com\android\server\DockObserver.java Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE;////移动APP完成之后,发出的广播(移动是指:APP2SD) Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;//正在移动APP时,发出的广播(移动是指:APP2SD) Intent.ACTION_GTALK_SERVICE_CONNECTED;//Gtalk已建立连接时发出的广播 Intent.ACTION_GTALK_SERVICE_DISCONNECTED;//Gtalk已断开连接时发出的广播 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;// 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_UNMOUNTABLE;// Intent.ACTION_MEDIA_UNMOUNTED// 广播:扩展介质存在,但是还没有被挂载 (mount)。  Intent.ACTION_NEW_OUTGOING_CALL;// 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_PROVIDER_CHANGED;// 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_USER_PRESENT;// Intent.ACTION_WALLPAPER_CHANGED;//设备墙纸已改变时发出的广播
0 0
原创粉丝点击