Android 内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。比如手机开机完成后会发出一条广播,电池的电能量发生变化会发出一条广播,系统时间发生改变也会发出一条广播,如果想要接收这些广播,就需要使用BroadcastReceiver 。
6.2.1 动态注册监听时间变化
我们可以根据自己感兴趣的广播,自由地注册 BroadcastReceiver ,这样当有相应的广播发出时,相应的BroadcastReceiver 就能接收到该广播,并可以在内部进行逻辑处理。注册BroadcastReceiver 的方式一般有两种:在代码中注册和在AndroidManifest.xml 中注册。在代码中注册为动态注册,在AndroidManifest.xml 中注册为静态注册。
动态注册其实很简单,创建一个类 继承 BroadcastReceiver 重写 onReceiver 方法就可以了。当有广播来临onReceiver 就会 执行。
我们新建一个 BroadcastTest 项目,然后修改MainActivity 的代码:
class MainActivity : AppCompatActivity() {
lateinit var timeChanggeReceiver: TimeChanggeReceiver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intentFilter = IntentFilter()
// 系统时间通知
intentFilter.addAction("android.intent.action.TIME_TICK")
timeChanggeReceiver = TimeChanggeReceiver()
registerReceiver(timeChanggeReceiver,intentFilter) // 注册 BroadcastReceiver
}
// 销毁时候解除注册 注销
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(timeChanggeReceiver)
}
inner class TimeChanggeReceiver : BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(context,"Time has changed",Toast.LENGTH_SHORT).show()
}
}
}
我们为广播添加了一个intentFilter 的action ,值为android.intent.action.TIME_TICK 系统时间发生变化时,系统发出的正式一条值为 android.intent.action.TIME_TICK 的广播,也就是说我们的 BroadcastReceiver 想要监听什么广播,这里就添加相应的action,要记得动态注册的广播一定要注销。
这就是动态注册广播的基本用法,如果想看完整的系统广播列表,可以到这个路径去查看:
<Android SDK>/platforms/<任意android api 版本>/data/broadcast_actions.txt
6.2.2 静态注册实现开启启动
动态注册的 BroadcastReceiver 可以自由地控制注册与注销,在灵活性方面有很大的优势。但它存在着一个缺点,即必须在程序启动之后才能接收广播,因为注册的逻辑是写在onCreate 方法中的。那么有没有什么办法可以让程序在未启动的情况下也能接收广播呢?这就需要使用静态注册的方式了。
其实从理论上来说,动态注册能监听到的系统广播,静态注册也应该能监听到,在过去的Android 系统中确实是这样的。但是由于大量恶意的应用程序利用这个机制在程序未启动的情况下监听系统广播,从而使任何应用都可以频繁地从后台被唤醒,严重影响了用户手机的电量和性能,因此Android 系统几乎每个版本都在削减静态注册BroadcastReceiver 的功能。
在Android 8.0系统之后,所以的隐式广播都不允许使用静态注册的方式来接收了。隐式广播指的是那些没有具体制定发送给哪个应用程序的广播,大多数系统广播属于隐式广播,但是少数特殊的系统广播目前仍然允许使用静态注册的方式来接收。这些特殊的系统广播列表详见:
https://developer.android.google.cn/guide/components/broadcast-exceptions.html
在这些特殊的系统广播当中,有一条值为 android.intent.action.BOOT_COMPLETED 的广播,这是一条开机广播,那么就使用它来举例学习吧。
我们需要实现的是一个开机启动的功能,所以肯定不能在程序中使用动态注册了,而应该使用静态注册的方式来接收开机广播,然后在onReceive 方法里执行相应的逻辑,这样就可以实现开机启动的功能了。
还是上一个项目,我们来用Android Studio 提供的快捷方式来创建 BroadcastReceiver,右键项目目录 -- New -- Other -- Broadcast Receiver
出现了这个页面,Exported 是表示是否允许这个BroadcastReceiver 接收本程序以外的广播,Enabled 表示是否启用这个BroadcastReceiver。都选,点Finish。
Android Studio 会自动帮我们创建一些配置,我们要知道静态注册的BroadcastReceiver 必须在AndroidManifest.xml 中进行注册,所以我们去看看。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.broadcasttest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true"></receiver>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
用法和activity 相似,现在的BroadcastReceiver 还无法接收开机启动的广播,需要修改,还记得动态注册中的intent-filter 吗,对就是这个,和Activity 配置action 相同,我们来动手操作吧。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.broadcasttest">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
就是监听这个广播就可以了,我们还需要添加一个权限,权限就是允许我们监听系统的开机广播,权限是为了保护用户的隐私安全着想的,如果用户不给权限,我们也就没有权利进行监听这个广播了。
我们在 BootCompleteReceiver 类中添加一个Toast 就可以啦,这里是逻辑代码,希望运行什么逻辑以后还得看需求。