个人所有文章整理在此篇,将陆续更新收录:知无涯,行者之路莫言终(我的编程之路)
1).BroadcastReceiver`静态`使用
2).BroadcastReceiver`动态`使用
3).BroadcastReceiver`有序`广播
4).BroadcastReceiver和`系统`行为的结合
5).小例子:使用BroadcastReceiver更新音乐播放器进度条
现在才发现BroadcastReceiver原来这么精简,纯源码才260 直接继承Object,没有实现接口,没有家庭背景,可以说是个很简单的类
类名:BroadcastReceiver 父类:Object 修饰:public abstract
实现的接口:[]
包名:android.content 依赖类个数:9
内部类/接口个数:1
源码行数:653 源码行数(除注释):260
属性个数:2 方法个数:36 public方法个数:36
静态使用也就是配置在
AndroidManifest.xml
中配置意图过滤器来匹配 关于intent的相关知识,见前一篇,这里不做解释
/**
* 作者:张风捷特烈<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>
---->[BrActivity#onCreate]------------------
id_btn_send.setOnClickListener {
val intent = Intent("www.toly1994.com.br.toast")
sendBroadcast(intent)
}
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)
}
广播接收者的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()
}
感觉从上面来看,BroadcastReceiver的onReceive确实耦合性非常低 外部只需要用intent和context.sendBroadcast就能触发它 但似乎BroadcastReceiver也没有太大的亮点,作用平平 为了说明他的亮点,现在我们新建一个app:
Anotherapp
可以发现在另一个app里也能正常使用这个广播 这就有点意思了,我在A项目中写了一个类,它的方法可以在B项目中触发 这就是静态广播厉害的地方,也是我第一次接触的跨进程通信 (这说明解耦到一定的境界,就天下与我同,然而我将无处不在,手动滑稽)
BroadcastReceiver动态使用分为注册和注销,
不需要在AndroidManifest.xml注册
只有在注册后和注销前的时间段才能使用,否则广播无效(即onReceive方法不会掉)
/**
* 注册广播
*/
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)
}
你说,哥就不注销怎么样?---答:异常呗 如果不注销,崩了一个异常,源码也好心提醒你要
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()//注销广播
}
你可能会说:就一个200多行的类,还搞那么多事...
动态注册的广播
|---优势:可以自由的控制注册和取消,有很大的灵活性。
|---劣势:只有在注册之后才能起作用,在Activity的onDestroy后如果未被注销,会报异常
----所以动态注册的广播存活时间最长也就约等于Activity的生命周期长度
静态注册的广播
|---优势:不受程序是否启动的约束,随时使用
|---劣势:优势同样也是劣势,无法取消,什么时候都能用
先讲个场景:男孩(Boy)说:一块石头的价值 1元 之后将石头给了雕刻家,并将预期的价值1000元传递给雕刻家 之后雕刻家将石头给了宝石家,并将预期的价值10W元传递给宝石家 之后宝石家将石头给了收藏家,并将预期的价值100W元传递给收藏家 收藏家向外称城自己的宝石价值100W
/**
* 作者:张风捷特烈<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()
}
}
/**
* 注册广播
*/
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)
}
* 说明:雕刻家
*/
class GraverBReceiver : BroadcastReceiver() {
/**
* 接收时调用的方法
*/
override fun onReceive(context: Context, intent: Intent) {
Toast.makeText(context, "雕刻家:$resultData", //[1]获取结果并展示
Toast.LENGTH_LONG).show()
abortBroadcast();//[2]终止广播
resultData = "价值10W元"//[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,
不需要注册!
以下皆使用动态注册,很多系统级的行为静态注册都是无效的
/**
* 作者:张风捷特烈<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)
}
注意权限:
<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)
}
这里传入一个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)
}
/**
* 作者:张风捷特烈<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+回调实现的 BroadcastReceiver本职就在于通知,在这里用BroadcastReceiver实现
音乐的播放进度
---->[常量类]-----------------------------
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()
}
其实也就是发广播-->收广播-->操作,用起来并不困难
至于BroadcastReceiver的源码,暂时就不读了(读了一下,没怎么读得通...),以后再开篇吧!