内容简介:现在才发现BroadcastReceiver原来这么精简,纯源码才260直接继承Object,没有实现接口,没有家庭背景,可以说是个很简单的类静态使用也就是配置在
1).BroadcastReceiver`静态`使用 2).BroadcastReceiver`动态`使用 3).BroadcastReceiver`有序`广播 4).BroadcastReceiver和`系统`行为的结合 5).小例子:使用BroadcastReceiver更新音乐播放器进度条 复制代码
2.BroadcastReceiver总览
现在才发现BroadcastReceiver原来这么精简,纯源码才260
直接继承Object,没有实现接口,没有家庭背景,可以说是个很简单的类
类名:BroadcastReceiver 父类:Object 修饰:public abstract 实现的接口:[] 包名:android.content 依赖类个数:9 内部类/接口个数:1 源码行数:653 源码行数(除注释):260 属性个数:2 方法个数:36 public方法个数:36 复制代码
一、BroadcastReceiver静态使用
静态使用也就是配置在 AndroidManifest.xml
中配置意图过滤器来匹配
关于intent的相关知识,见前一篇,这里不做解释
1.写一个类继承自BroadcastReceiver
/** * 作者:张风捷特烈<br></br> * 时间:2019/1/21/021:16:53<br></br> * 邮箱:1981462002@qq.com<br></br> * 说明:谈一个吐司的BroadcastReceiver */ class ToastBroadcastReceiver : BroadcastReceiver() { /** * 接收时调用的方法 */ override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context, "Toly", Toast.LENGTH_SHORT).show() } } ---->[app/src/main/AndroidManifest.xml]------------------ <receiver android:name=".receiver.receiver.ToastBroadcastReceiver"> <intent-filter> <action android:name="www.toly1994.com.br.toast"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </receiver> 复制代码
2.测试的Activity
---->[BrActivity#onCreate]------------------ id_btn_send.setOnClickListener { val intent = Intent("www.toly1994.com.br.toast") sendBroadcast(intent) } 复制代码
3.静态广播在Android8.0+
intent必须指定广播的component,才有效
---->[BrActivity#onCreate]------------------ id_btn_send.setOnClickListener { val intent = Intent("www.toly1994.com.br.toast") intent.component = ComponentName( "com.toly1994.tolyservice",//项目包名 "com.toly1994.tolyservice.receiver.receiver.ToastBroadcastReceiver"//广播接收者全类名 ) sendBroadcast(intent) } 复制代码
4.静态广播中的数据获取
广播接收者的onReceive回调中有intent: Intent,你应该明白怎么传数据了吧
---->[BrActivity#onCreate]------------------ id_btn_send.setOnClickListener { val intent = Intent("www.toly1994.com.br.toast") id_et_txt.text //为intent添加数据 intent.putExtra("toast_data", id_et_txt.text.toString()) intent.component = ComponentName( "com.toly1994.tolyservice",//项目包名 "com.toly1994.tolyservice.receiver.receiver.ToastBroadcastReceiver"//广播接收者全类名 ) sendBroadcast(intent) } ---->[ToastBroadcastReceiver]------------------ /** * 接收时调用的方法 */ override fun onReceive(context: Context, intent: Intent) { val data = intent.getStringExtra("toast_data") //data?:"NO MSG"表示如果data是空,就取"NO MSG" Toast.makeText(context, data?:"NO MSG", Toast.LENGTH_SHORT).show() } 复制代码
5.BroadcastReciver有什么用?
感觉从上面来看,BroadcastReciver的onReceive确实耦合性非常低
外部只需要用intent和context.sendBroadcast就能触发它
但似乎BroadcastReciver也没有太大的亮点,作用平平
为了说明他的亮点,现在我们新建一个app: Anotherapp
可以发现在另一个app里也能正常使用这个广播
这就有点意思了,我在A项目中写了一个类,它的方法可以在B项目中触发
这就是静态广播厉害的地方,也是我第一次接触的跨进程通信
(这说明解耦到一定的境界,就天下与我同,然而我将无处不在,手动滑稽)
二、BroadcastReceiver动态使用
BroadcastReceiver动态使用分为注册和注销, 不需要在AndroidManifest.xml注册
只有在注册后和注销前的时间段才能使用,否则广播无效(即onReceive方法不会掉)
1.注册广播与发送消息
/** * 注册广播 */ private fun register() { val filter = IntentFilter()//创建意图过滤器 filter.addAction("www.toly1994.com.br.toast2")//添加意图 mReceiver = Toast2BroadcastReceiver()//创建 Toast2BroadcastReceiver registerReceiver(mReceiver, filter)//注册 } /** * 发送广播 */ private fun sendMsg() { val intent = Intent() intent.action = "www.toly1994.com.br.toast2" intent.putExtra("toast_data", id_et_txt.text.toString()) sendBroadcast(intent) } 复制代码
2.注销广播
你说,哥就不注销怎么样?---答:异常呗
如果不注销,崩了一个异常,源码也好心提醒你要 unregisterReceiver
2019-01-22 14:10:50.940 4892-4892/com.toly1994.tolyservice E/ActivityThread: Activity com.toly1994.tolyservice.receiver.BrActivity has leaked IntentReceiver com.toly1994.tolyservice.receiver.receiver.Toast2BroadcastReceiver@32500e2 that was originally registered here. Are you missing a call to unregisterReceiver()? at android.app.LoadedApk$ReceiverDispatcher.<init>(LoadedApk.java:1333) at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:1114) at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1405) at android.app.ContextImpl.registerReceiver(ContextImpl.java:1378) at android.app.ContextImpl.registerReceiver(ContextImpl.java:1366) at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:603) at com.toly1994.tolyservice.receiver.BrActivity.onCreate(BrActivity.kt:27) 复制代码
/** * 注销广播 */ private fun unRegister() { unregisterReceiver(mReceiver); } override fun onDestroy() { super.onDestroy() unRegister()//注销广播 } 复制代码
3.静态和动态广播的区别
你可能会说:就一个200多行的类,还搞那么多事...
动态注册的广播 |---优势:可以自由的控制注册和取消,有很大的灵活性。 |---劣势:只有在注册之后才能起作用,在Activity的onDestroy后如果未被注销,会报异常 ----所以动态注册的广播存活时间最长也就约等于Activity的生命周期长度 静态注册的广播 |---优势:不受程序是否启动的约束,随时使用 |---劣势:优势同样也是劣势,无法取消,什么时候都能用 复制代码
三、BroadcastReceiver有序广播
先讲个场景:男孩(Boy)说:一块石头的价值 1元
之后将石头给了雕刻家,并将预期的价值1000元传递给雕刻家
之后雕刻家将石头给了宝石家,并将预期的价值10W元传递给宝石家
之后宝石家将石头给了收藏家,并将预期的价值100W元传递给收藏家
收藏家向外称城自己的宝石价值100W
1.有序广播(没有指定顺序时,按注册顺序)
1.1:四个广播接收者
/** * 作者:张风捷特烈<br></br> * 时间:2019/1/21/021:16:53<br></br> * 邮箱:1981462002@qq.com<br></br> * 说明:男孩 */ class BoyBReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context, "男孩:$resultData",//[1]获取结果并展示 Toast.LENGTH_LONG ).show() // abortBroadcast();//[2]终止广播 resultData = "价值1000元" //[3]传递数据---给下一个广播 } } /** * 说明:雕刻家 */ class GraverBReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context, "雕刻家:$resultData", //[1]获取结果并展示 Toast.LENGTH_LONG).show() // abortBroadcast();//[2]终止广播 resultData = "价值10W元"//[3]传递数据---给下一个广播 } } /** * 说明:宝石家 */ class RubyManBReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context, "宝石家:$resultData", Toast.LENGTH_LONG).show() // abortBroadcast();//[2]终止广播 resultData = "价值100W元"//[3]传递数据---给下一个广播 } } /** * 说明:收藏家 */ class CollectorBReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context, "收藏家:$resultData", //获取结果并展示 Toast.LENGTH_LONG).show() } } 复制代码
1.2.动态注册并发送有序广播
/** * 注册广播 */ private fun register() { val filter = IntentFilter()//创建意图过滤器 filter.addAction("www.toly1994.com.br.toast2")//添加意图 boyReceiver = BoyBReceiver() graverReceiver = GraverBReceiver() rubyManReceiver = RubyManBReceiver() registerReceiver(boyReceiver, filter)//注册 registerReceiver(graverReceiver, filter)//注册 registerReceiver(rubyManReceiver, filter)//注册 } /** * 发送有序广播 */ private fun sendOrder() { val intent = Intent() intent.action = "www.toly1994.com.br.toast2" val collectorBReceiver = CollectorBReceiver() sendOrderedBroadcast( intent, null, collectorBReceiver, null, 1, "价值1元", null ) } /** * 注销广播 */ private fun unRegister() { unregisterReceiver(boyReceiver) unregisterReceiver(graverReceiver) unregisterReceiver(rubyManReceiver) } 复制代码
2.中途终止广播有序广播
* 说明:雕刻家 */ class GraverBReceiver : BroadcastReceiver() { /** * 接收时调用的方法 */ override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context, "雕刻家:$resultData", //[1]获取结果并展示 Toast.LENGTH_LONG).show() abortBroadcast();//[2]终止广播 resultData = "价值10W元"//[3]传递数据---给下一个广播 } } 复制代码
3.自定义广播顺序
/** * 注册广播 */ private fun register() { boyReceiver = BoyBReceiver() val boyFilter = IntentFilter()//创建意图过滤器 boyFilter.addAction("www.toly1994.com.br.toast2")//添加意图 boyFilter.priority = 10//指定过滤器优先级 graverReceiver = GraverBReceiver() val graverFilter = IntentFilter()//创建意图过滤器 graverFilter.addAction("www.toly1994.com.br.toast2")//添加意图 graverFilter.priority = 20//指定过滤器优先级 rubyManReceiver = RubyManBReceiver() val rubyManFilter = IntentFilter()//创建意图过滤器 rubyManFilter.addAction("www.toly1994.com.br.toast2")//添加意图 rubyManFilter.priority = 21//指定过滤器优先级 registerReceiver(boyReceiver, boyFilter)//注册 registerReceiver(graverReceiver, graverFilter)//注册 registerReceiver(rubyManReceiver, rubyManFilter)//注册 } 复制代码
上面是BroadcastReceiver有序广播的动态注册形式的代码,
静态注册在AndroidManifest.xml里配置类似,就不废话了
还有一点注意的是sendOrderedBroadcast方法调用时传入的BroadcastReceiver
为最后调用的BroadcastReceiver, 不需要注册!
四、广播和系统行为的结合
以下皆使用动态注册,很多系统级的行为静态注册都是无效的
1.开屏锁屏广播
/** * 作者:张风捷特烈<br></br> * 时间:2019/1/22/022:16:43<br></br> * 邮箱:1981462002@qq.com<br></br> * 说明:开屏锁屏广播 */ class ScreenBReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { //[1]获取到当前广播的事件类型 val action = intent.action //[2]对当前广播事件类型做一个判断 if ("android.intent.action.SCREEN_OFF" == action) { Log.e(TAG, "屏幕锁屏了") } else if ("android.intent.action.SCREEN_ON" == action) { Log.e(TAG, "屏幕解锁了") } } companion object { private const val TAG = "ScreenBReceiver" } } ---->[ScreenBrActivity使用方法]------------------------------------ /** * 动态的去注册屏幕解锁和锁屏的广播 */ private fun register() { // [1]动态的去注册屏幕解锁和锁屏的广播 mScreenReceiver = ScreenBReceiver() // [2]创建intent-filter对象 val filter = IntentFilter() // [3]添加要注册的action filter.addAction("android.intent.action.SCREEN_OFF") filter.addAction("android.intent.action.SCREEN_ON") // [4]注册广播接收者 registerReceiver(mScreenReceiver, filter) } 复制代码
2.短信监听广播
注意权限: <uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
/** * 作者:张风捷特烈<br></br> * 时间:2019/1/22/022:16:43<br></br> * 邮箱:1981462002@qq.com<br></br> * 说明:短信监听广播 */ class SMSBReceiver : BroadcastReceiver() { //当短信到来的时候 就会执行这个方法 override fun onReceive(context: Context, intent: Intent) { //[1]获取发短信送的号码 和内容 val objects = intent.extras!!.get("pdus") as Array<*> val format = intent.getStringExtra("format") for (pdu in objects) { //[2]获取smsmessage实例 val smsMessage = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { SmsMessage.createFromPdu(pdu as ByteArray, format) } else { SmsMessage.createFromPdu(pdu as ByteArray) } //[3]获取发送短信的内容 val body = smsMessage.messageBody val date = Date(smsMessage.timestampMillis)//时间 val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA) //[4]获取发送者 val address = smsMessage.originatingAddress val receiveTime = format.format(date) Log.e("SMSBReceiver", "body:$body---$address---$receiveTime") } } } ---->[SMSBrActivity使用方法]------------------------------------ /** * 动态注册短信广播接收者 */ private fun register() { //注册短信广播接收者 val smsFilter = IntentFilter() smsFilter.addAction("android.provider.Telephony.SMS_RECEIVED") mSmsReceiver = SMSBReceiver() registerReceiver(mSmsReceiver, smsFilter) } 复制代码
3.监听电量变化广播
这里传入一个Textview用于显示电量
/** * 作者:张风捷特烈<br></br> * 时间:2019/1/22/022:16:43<br></br> * 邮箱:1981462002@qq.com<br></br> * 说明:监听电量变化 */ class BatteryBReceiver(private val mTV:TextView ) : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { // 当前电量 val currLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) // 总电量 val total = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 1) val percent = currLevel * 100 / total Log.e("BatteryBReceiver", "battery: $percent%") mTV.setTextColor(randomRGB()) mTV.text = "battery: $percent%" } /** * 返回随机颜色 * * @return 随机颜色 */ fun randomRGB(): Int { val random = Random() val r = 30 + random.nextInt(200) val g = 30 + random.nextInt(200) val b = 30 + random.nextInt(200) return Color.rgb(r, g, b) } } ---->[BatteryBrActivity使用方法]------------------------------------ /** * 动态电量广播接收者 */ private fun register() { val filter = IntentFilter() filter.addAction(Intent.ACTION_BATTERY_CHANGED) mBatteryChangeReceiver = BatteryBReceiver(id_tv_info) registerReceiver(mBatteryChangeReceiver, filter) } 复制代码
4.app安装/卸载改变时广播监听
/** * 作者:张风捷特烈<br></br> * 时间:2019/1/22/022:16:43<br></br> * 邮箱:1981462002@qq.com<br></br> * 说明:app安装/卸载改变时广播监听 */ class AppBReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val action = intent.action val uri = intent.data if (action == "android.intent.action.PACKAGE_ADDED") { Log.e("AppBReceiver", uri.toString() + "被安装了") } else if (action == "android.intent.action.PACKAGE_REPLACED") { Log.e("AppBReceiver", uri.toString() + "被更新了") } else if (action == "android.intent.action.PACKAGE_REMOVED") { Log.e("AppBReceiver", uri.toString() + "被卸载了") } } } ---->[AppBrActivity使用方法]------------------------------------ /** * 动态注册app安装/卸载改变时广播监听 */ private fun register() { val filter = IntentFilter() filter.addAction("android.intent.action.PACKAGE_ADDED") filter.addAction("android.intent.action.PACKAGE_REPLACED") filter.addAction("android.intent.action.PACKAGE_REMOVED") filter.addDataScheme("package") mAppReceiver = AppBReceiver() registerReceiver(mAppReceiver, filter) } //但是貌似这个用动态注册并不怎么有用 //因为一般卸载,安装都不是在当前Activity中,加了一下静态,便可以了 //注意,在测试中发现,只加静态的配置也是无效的 <receiver android:name=".receiver.receiver.AppBReceiver"> <intent-filter > <action android:name="android.intent.action.PACKAGE_ADDED"/> <action android:name="android.intent.action.PACKAGE_REPLACED"/> <action android:name="android.intent.action.PACKAGE_REMOVED"/> <data android:scheme="package"/> </intent-filter> </receiver> 复制代码
还有一些系统行为套路都差不多,需要的时候查查对应的action就行了
五、使用广播更新音乐进度条
在 绝命暗杀官[-Service-] 中实现过一个音乐播放条,其中音乐的播放进度是靠Handler+回调实现的
BroadcastReciver本职就在于通知,在这里用BroadcastReciver实现 音乐的播放进度
---->[常量类]----------------------------- public class Cons { //广播更新进度--数据 public static final String DATA_MUSIC_POSITION = "data_music_position"; //广播更新进度--Action public static final String ACTION_UPDATE = "action_update"; } ---->[MusicPlayerWithBrStub]----------------------------- mTimer.schedule(new TimerTask() { @Override public void run() { if (mPlayer.isPlaying()) { int pos = mPlayer.getCurrentPosition(); int duration = mPlayer.getDuration(); //发送广播更新进度 ---> Intent intent = new Intent(Cons.ACTION_UPDATE); ---> int progress = (int) (pos * 100.f / duration); ---> intent.putExtra(Cons.DATA_MUSIC_POSITION, progress); ---> mContext.sendBroadcast(intent); } } }, 0, 1000); ---->[MusicActivity#registerReceiver]----------------------------- |-- 这里我新建一个类,你也可以直接在Activity中建个内部类,要简单些 public class UpdateReceiver extends BroadcastReceiver { @Nullable private ProgressView progressView; public UpdateReceiver(@Nullable ProgressView progressView) { this.progressView = progressView; } @Override public void onReceive(Context context, Intent intent) { if (Cons.ACTION_UPDATE.equals(intent.getAction())) { int progress = intent.getIntExtra(Cons.DATA_MUSIC_POSITION, 0); if (progressView != null) { ---> progressView.setProgress(progress); } } } } /** * 注册广播 */ ---->[MusicActivity#registerReceiver]----------------------------- private fun registerReceiver() { mReceiver = UpdateReceiver(id_pv_pre) val filter = IntentFilter() filter.addAction(Cons.ACTION_UPDATE) registerReceiver(mReceiver, filter)//注册 } ---->[MusicActivity#onDestroy]----------------------------- override fun onDestroy() { super.onDestroy() unregisterReceiver(mReceiver)//注销广播 mMusicPlayer.release() } 复制代码
其实也就是发广播-->收广播-->操作,用起来并不困难
至于BroadcastReciver的源码,暂时就不读了(读了一下,没怎么读得通...),以后再开篇吧!
后记:捷文规范
1.本文成长记录及勘误表
项目源码 | 日期 | 附录 |
---|---|---|
V0.1--无 | 2018-2-27 | 无 |
发布名: Android点将台:传令官[-BroadcastReciver-]
捷文链接: juejin.im/post/5c469b…
2.更多关于我
笔名 | 微信 | |
---|---|---|
张风捷特烈 | 1981462002 | zdl1994328 |
我的github: github.com/toly1994328
我的简书: www.jianshu.com/u/e4e52c116…
我的简书: www.jianshu.com/u/e4e52c116…
个人网站:www.toly1994.com
3.声明
1----本文由张风捷特烈原创,转载请注明
2----欢迎广大编程爱好者共同交流
3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持
以上所述就是小编给大家介绍的《Android点将台:传令官[-BroadcastReciver-](使用级)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Android点将台:烽火狼烟[-Handler-]
- Android点将台:济世儒侠[-ContentProvider-]
- Android点将台:颜值担当[-Activity-]
- Android点将台:绝命暗杀官[-Service-]
- Android点将台:金科玉律[-AIDL-]
- Android 点将台:撒豆成兵[- Fragment -]
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
PHP 6与MySQL 5基础教程
(美)厄尔曼 / 陈宗斌 等 / 人民邮电出版社 / 2008-11-1 / 65.00元
本书是一部经典的入门级著作,采用基于任务的方法来讲授PHP和MySQL,使用大量图片指导读者深入学习语言,并向读者展示了如何构造动态Web站点。书中用简洁、直观的步骤和讲解提供了学习任务和概念的最快方式。通过学习本书,读者可以快速、高效地掌握PHP和MySQL,成为一位构建Web站点的高手。 本书适合初中级Web应用开发和设计人员阅读。 本书是讲述PHP和MySQL技术的畅销书,以深入......一起来看看 《PHP 6与MySQL 5基础教程》 这本书的介绍吧!