四大组件---BroadcastReceiver
一、为什么要有广播接收者
【1】 android系统内部已经定义好一些广播事件,外拨电话,短信到来,sd卡状态,电池电量
【2】 使用broadcaseReceiver接收系统已经定义好的事件
【3】 定义广播接收者的目的是为了方便开发者进行开发
【4】 类型于java中的观察者模式
二、系统广播例子
【1】 外拨电话(ip拨号器):
1.定义一个外拨的广播接收者,OutgoingReceiver继承BroadcastReceiver
2.在清单文件中注册
<receiver android:name=".OutGoingCallReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
还必须申请权限
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
3.如果是6.0以上的,还需要动态申请权限Manifest.PROCESS_OUTGOING_CALLS
4.在java文件中,获取将要拨打的号码,将号码修改,再设置回去
/**
* 接收外拨号码
*/
override fun onReceive(context: Context?, intent: Intent?) {
// 获取号码
val resultData = resultData
println("resultData:$resultData")
// 加上区号
setResultData("0754$resultData")
}
【2】 sd卡
1.定义一个监听sd卡的广播接收者
2.在清单文件中注册该广播接收者
<receiver android:name=".SdReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
<!--需要配置一个data 约束类型是file,因为sd卡中的数据都是file-->
<data android:scheme="file"/>
</intent-filter>
</receiver>
【3】 短信接收
1.定义一个短信接收的广播
2.在清单文件中注册该广播,添加意图过滤器
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
此action已经被谷歌工程师屏蔽了,但是功能还是存在的
3.添加短信接收的权限
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
此权限需要动态申请
4.java代码
class SmsReceiver : BroadcastReceiver() {
// 短信到来的时候执行
override fun onReceive(context: Context?, intent: Intent?) {
val pdus = intent?.extras?.get("pdus")
if (pdus is Array<*>) {
pdus.forEach {
val message = SmsMessage.createFromPdu(it as ByteArray?)
val messageBody = message.messageBody
val originatingAddress = message.originatingAddress
Toast.makeText(context, "接收到短信:\n$originatingAddress:$messageBody", Toast.LENGTH_LONG)
.show()
}
}
}
}
【4】 app的安装和卸载
1.定义一个接收app的安装和卸载的广播
2.在清单文件中注册该广播,添加意图过滤器
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package"/>
</intent-filter>
注意:此广播需要配置data中的scheme,值为package
3.java代码
class AppStateReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
"android.intent.action.PACKAGE_ADDED" -> {
println("add")
}
"android.intent.action.PACKAGE_REMOVED" -> {
println("remove")
}
}
}
}
4.注意:这个广播属于隐式广播,在android8.0以上对这些隐式广播作了限制,在清单文件中静态注册是无效果的,需要动态注册,如果非要进行静态注册的话,需要将targetSdkVersion设在26以下
5.动态注册:
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED)
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED)
intentFilter.addDataScheme("package")
registerReceiver(appStateReceiver, intentFilter)
【5】 开机启动
1.定义一个接收开机启动的广播接收者
2.在清单文件中注册该广播接收者,然后添加意图过滤器
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
3.还需要添加权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
此权限不需要动态申请
三、自定义广播
1.无序广播
android 8.0以上需要
intent.component= ComponentName(this,"com.wzh.a02_broadcastreceiverdemo.order_broardcastreceiver.ProvinceReceiver")
sendBroadcast(intent),不管有没有接收者,都会发送 不可以被中止,数据不可以被修改
2.有序广播
/**
* intent
*
* receiverPermission 接收的权限
*
* resultReceiver 最终的receiver,不需要在清单文件中配置
*
* scheduler handle
*
* initialCode 初始化码
*
* initialData 初始化数据
*
* initialExtras 额外的数据
*/
sendOrderedBroadcast(intent4, null, null, null, 1, "发送大米了", null)
有序广播可以被中止,数据可以被修改 android 8.0以上,发送有序广播,暂时没有合适的解决方案
四、特殊的广播接收者
操作比较频繁的广播事件,屏幕的锁屏和解锁,电池电量的变化,这些广播接收者在清单文件中注册是无效的
android.intent.action.SCREEN_ON
android.intent.action.SCREEN_OFF
android.intent.action.BATTERY_CHANGED
android.intent.action.CONFIGURATION_CHANGED
android.intent.action.TIME_TICK