Android四大组件——BroadcastReceiver——动态注册和静态注册
广播的用处:
1.实现了不同程序之间的数据传输与共享,因为只要是和发送广播的action相同的接受者都能接受这个广播。典型的应用就是android自带的短信,电话等等广播,只要我们实现了他们的action的广播,那么我们就能接收他们的数据了,以便做出一些处理。比如说拦截系统短信,拦截骚扰电话等等。
2.起到了一个通知的作用,比如在service中要通知主程序,更新主程序的UI等。因为service是没有界面的,所以不能直接获得主程序中的控件,这样我们就只能在主程序中实现一个广播接受者专门用来接受service发过来的数据和通知了。
广播的分类:
- 标准广播:是一种完全异步执行的广播,在广播发出之后,所有的BroadcastReceiver几乎会同一时间收到这条广播消息,因此她们之间没有先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。
- 有序广播:是一种同步执行的广播,在广播发出之后,同一时刻只会有一个BroadcastReceiver能够收到这条广播消息,当这个BroadcastReceiver中的逻辑执行完毕后,广播才会继续传递。所以此时的BroadcastReceiver是有先后顺序的,优先级高的BroadcastReceiver就可以先收到广播。并且前面的BroadcastReceiver还可以截断正在传递的广播,这样后面的BroadcastReceiver就无法收到广播了。
实战:
广播需要注册,分为静态注册和动态注册两种。
- 静态注册:在AndroidManifest.xml中注册。
- 动态注册:在代码中注册。
1.动态注册监听电量变化的广播(注意:电量变化不能静态注册)
步骤:新建一个类,让它继承BroadcastReceiver,并重写父类的onReceive()方法就行了。这样当有广播到来时,onReceive()方法就会得到执行,具体的逻辑可在该方法中处理。
package com.java.androidstudy; import androidx.appcompat.app.AppCompatActivity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.util.Log; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //我们要收听的频道是:电量变化 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);//电量变化,想监听什么广播,就添加相应的action //创建接收者 BatteryLeveReceiver batteryLeveReceiver = new BatteryLeveReceiver(); //动态注册广播 this.registerReceiver(batteryLeveReceiver,intentFilter); } //第一步,创建一个广播接收者,继承自BroadcastReceiver private class BatteryLeveReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { //在这里写接收到广播后的逻辑处理 String action = intent.getAction(); Log.d(TAG,"收到了电量变化的广播,action is ==>"+action); } } }
监听电量变化的广播还需要打开权限:
<uses-permission android:name="android.permission.BATTERY_STATS" />
运行后,在模拟器上拖动电量:
观察日志:
在拖动电量变化时,成功监听到了该广播。
现在我们将电量变化显示出来:
修改代码如下:
//第一步,创建一个广播接收者,继承自BroadcastReceiver private class BatteryLeveReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { //在这里写接收到广播后的逻辑处理 String action = intent.getAction(); Log.d(TAG,"收到了电量变化的广播,action is ==>"+action); Log.d(TAG,"当前电量:"+intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0));//获取电量,可戳进BatteryManager的源代码看看 } }
拖动电量后观察日志:
OK,已经成功获取了。
动态注册的BroadcastReceiver一定要取消注册才行,这里我们是在onDestroy()方法中通过调用unregisterReceiver()方法来实现的。代码如下:
//取消广播注册,否则会造成内存卡顿
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(batteryLeveReceiver);
}
2.静态注册广播监听开机启动
动态注册的BroadcastReceiver可以自由控制注册和注销,但必须在程序启动之后才能接收广播,因为注册的逻辑是写在onCreate()中的。
静态注册的BroadcastReceiver可以在程序未启动的情况下也能接收广播。
在Android8.0以后,所有隐式广播都不允许使用静态注册的方式来接收了。隐式广播指的是那些没有指定具体发送给哪个应用程序的广播,大多数系统广播属于隐式广播。少数特殊的系统广播目前仍然允许使用静态注册的方式来接收。如开机广播。
步骤:新建BootCompleteReceiver类,使之继承BroadcastReceiver,代码如下:
//第一步:新建BootCompleteReceiver类 public class BootCompleteReceiver extends BroadcastReceiver { private static final String TAG="BootCompleteReceiver"; @Override public void onReceive(Context context, Intent intent) { //第三步,收到开机广播后做的事情 String action = intent.getAction(); Log.d(TAG,"action is =="+action); Log.d(TAG,"开机完成"); Toast.makeText(context,"收到开机完成的广播",Toast.LENGTH_SHORT).show(); //静态注册,不需要启动程序也可以接收到广播,不需要取消注册。 } }
然后,我们需要在AndroidManifest.xml文件中<application>标签内进行开机广播的静态注册。
代码如下:
<receiver android:name=".BootCompleteReceiver" android:enabled="true" android:exported="true"> <!-- 第二步,静态注册action --> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
此外,我们还需要打开开机广播的权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
现在运行程序后重启模拟器,日志截图如下:
可以看到,已经成功获取到了开机的广播信息。