定义
广播,是一个全局的监听器,属于Android四大组件之一。Android广播分为两个角色:广播发送者、广播接收者。
应用场景
1、App接受系统发出的系统广播;
2、不同App之间的组件之间消息通信;
3、同一个App的不同组件之间的消息通信;
广播类型
1、标准广播
2、有序广播
监听电量变化状态(例子一)
1、广播接收者
小技巧:.notnull自动补全
报错点:setText不能传int类型
/**
* 第一步,创建一个广告接收者,继承自BroadcastReceiver
*/
private class BatteryLevelReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG,"action is == " +action);
if (Intent.ACTION_BATTERY_CHANGED.equals(action)){
int currentLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0);
Log.d(TAG,"当前的电量为:"+currentLevel);
//快捷键.notnull
if (mBatteryLevel != null) {
//mBatteryLevel.setText(intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0)); 报错了,不能传int变量,必须为String
mBatteryLevel.setText("当前的电量为:" + currentLevel);
}
int maxBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_SCALE,0);
float batteryPercent = currentLevel * 100.0f / maxBatteryLevel;
Log.d(TAG,"当前的电量百分比为:"+batteryPercent + "%");
}
}
}
2、添加权限
<uses-permission android:name="android.permission.BATTERY_STATS"/>
3、注册广播(动态注册)
小技巧:对代码块进行右键->Refactor->Extract->method 可以提炼函数;
private void registerBatteryReceiver() {
//注册广播:动态注册
//第二步,创建意图过滤器
IntentFilter intentFilter = new IntentFilter();
//第三步,添加要监听的广播action
//设置频道
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
//第四步,创建广播者,并且设置成成员变量,以便于取消注册,释放资源
batteryLevelReceiver = new BatteryLevelReceiver();
//第五步,注册广播接收者
this.registerReceiver(batteryLevelReceiver,intentFilter);
}
4、取消注册广播
小技巧:Ctrl + o select methods to Override选择方法重写;
@Override
protected void onDestroy() {
super.onDestroy();
//第六步,取消广播注册,否则会导致内存泄露
if(batteryLevelReceiver != null){
unregisterReceiver(batteryLevelReceiver);
batteryLevelReceiver = null;
Log.d(TAG,"unregister receive");
}
}
5、模拟电量的adb 命令
dumpsys battery help
Battery service (battery) commands:
help
Print this help text.
set [ac|usb|wireless|status|level|invalid] <value>
Force a battery property value, freezing battery state.
unplug
Force battery unplugged, freezing battery state.
reset
Unfreeze battery state, returning to current hardware values.
监听开机广播(例子二)
1、广播接收者
新建一个类,接收到开机广播后自启动APK;
public class BootCompleteReceiver extends BroadcastReceiver {
private static final String TAG = "BootCompleteReceiver";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_BOOT_COMPLETED.equals(action)){
Toast.makeText(context,"接收到开机广播",Toast.LENGTH_SHORT).show();
Log.d(TAG,"接收到开机广播");
Intent autonStart = new Intent(context,MainActivity.class);
context.startActivity(autonStart);
}
}
}
2、添加权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
3、注册广播(静态注册)
android:priority="1000",可以提高优先级,会减少APP接受到广播的时间;
<receiver
android:name=".BootCompleteReceiver">
<intent-filter android:priority="1000">
<action android:name= "android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
动态注册(例子一)和静态注册(例子二)的区别
1、某些action不支持静态注册,在Intent.java的注释中会有如下的说明:
You <em>cannot</em> receive this through components declared
* in manifests, only by explicitly registering for it with
* {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2、动态注册会受到activity的生命周期影响,销毁后不再监听广播(动态注册的广播要想一直监听可以注册到server里面区监听),不容易出现内存泄漏;静态注册的广播,即使Activity销毁了,仍然可以收到广播。即使杀死进程,仍然可以收到广播。
3、Android8.0以上平台,应用不能对大部分广播进行静态注册;
监听应用的安装和卸载(例子三)
1、广播接收者
public class AppStateChangeReceiver extends BroadcastReceiver {
private static final String TAG = "AppStateChangeReceiver";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_PACKAGE_ADDED.equals(action)){
Log.d(TAG, "有应用安装了,它的相关信息是:" + intent.getData());
}else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)){
Log.d(TAG, "有应用卸载了,它的相关信息是:" + intent.getData());
}
}
}
2、添加权限
无需添加权限,一般我们调试的时候可以先不加权限,当报错的时候我们再会过来重新加上;
3、静态注册
必须要加上data标签,否则会接收不到广播;
<receiver
android:name=".AppStateChangeReceiver">
<intent-filter>
<!--应用安装-->
<action android:name="android.intent.action.PACKAGE_ADDED"></action>
<!--应用卸载-->
<action android:name="android.intent.action.PACKAGE_REMOVED"></action>
<data android:scheme="package"/>
</intent-filter>
</receiver>
4、小结:通过应用安装、应用卸载广播我们可以得知哪些被卸载或者被安装的APK包名,之前遇到过一个系统开发需求就是,当客户的APK OTA升级成功之后重启系统,就可以用这个方法;接收应用安装的系统广播,并判断或者的getData包名是否为指定的包名,若是则重启;
发送自定义标准广播和接收(例子四)
1、发送自定义标准广播
新建一个SendBroadcaseActivity以及布局文件,方便调试我们把SendBroadcaseActivity作为启动activity,即把下面的代码块复制到SendBroadcaseActivity的声明中;
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
hint代表当输入框为空时的提示语;
onClick代表当点击按钮时执行的方法;
<EditText
android:id="@+id/be_send_msg_input_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入你的广播信息"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="sendBroadcastMsg"
android:text="发送一条广播通知"/>
public class SendBroadcaseActivity extends Activity {
private EditText mInputBox;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_send);
mInputBox = this.findViewById(R.id.be_send_msg_input_box);
}
/**
* 当我们点击按钮后,会执行下面的方法
*/
public void sendBroadcastMsg(View view){
String content = mInputBox.getText().toString();
Intent intent = new Intent();
intent.setAction(Constants.ACTION_SEND_MSG);
intent.putExtra(Constants.KEY_CONTENT,content);
sendBroadcast(intent);
}
}
一般自定义广播action命名为包名.常量比如:com.example.broadcastdemo.SEN_MSG
这里因为action名和键名都为常量,我们新建一个Constants.java存储常量,方便合作开发。
package com.example.broadcastdemo;
public class Constants {
public static final String ACTION_SEND_MSG = "com.example.broadcastdemo.SEND_MSG";
public static final String KEY_CONTENT = "content";
}
2、广播接收者
新建MessageReceiver 作为广播接收者
public class MessageReceiver extends BroadcastReceiver {
private static final String TAG = "MessageReceiver";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "action :" + action);
String content = intent.getStringExtra(Constants.KEY_CONTENT);
Log.d(TAG, "message :" + content);
}
}
别忘了注册广播
<receiver android:name=".MessageReceiver">
<intent-filter>
<action android:name="com.example.broadcastdemo.SEND_MSG"></action>
</intent-filter>
</receiver>
发送自定义有序广播和接收(例子五-android:priority优先级)
1、编写三个继承Broadcast的类进行测试,并对他们进行静态注册,同时用android:priority属性设置不同的优先级;范围:-1000~1000,默认值为0;
sendOrderedBroadcast的receiverPermission参数先设置为null,在例子七讲解;
public void SendOrderBroadCastMsg (View view){
Intent intent = new Intent();
intent.setAction(Constants.ACTION_SEND_ORDER_BROADCAST);
sendOrderedBroadcast(intent,null);
}
<receiver android:name=".HightLevelReceiver">
<intent-filter android:priority="1000">
<action android:name="com.example.broadcastdemo.SEND_ORDER_BROADCAST"></action>
</intent-filter>
</receiver>
<receiver android:name=".DefaultLevelReceiver">
<intent-filter android:priority="0">
<action android:name="com.example.broadcastdemo.SEND_ORDER_BROADCAST"></action>
</intent-filter>
</receiver>
<receiver android:name=".LowLevelReceiver">
<intent-filter android:priority="-1000">
<action android:name="com.example.broadcastdemo.SEND_ORDER_BROADCAST"></action>
</intent-filter>
</receiver>
2、测试结果
1970-01-01 08:01:48.111 4876-4876/com.example.broadcastdemo D/HightLevelReceiver: Hight Level action:com.example.broadcastdemo.SEND_ORDER_BROADCAST
1970-01-01 08:01:48.113 4876-4876/com.example.broadcastdemo D/DefaultLevelReceiver: default level: com.example.broadcastdemo.SEND_ORDER_BROADCAST
1970-01-01 08:01:48.116 4876-4876/com.example.broadcastdemo D/LowLevelReceiver: Low Level action:com.example.broadcastdemo.SEND_ORDER_BROADCAST
留一个疑问,是否可以设置 android:priority优先级属性的广播就是有序广播呢?那前面的系统开机广播算不算有序广播?
有序广播的终止广播和修改广播内容(例子六)
1、终止广播
直接修改HightLevelReceiver的onReceiver的函数让广播终止;
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "Hight Level action:" + action);
//终止广播
abortBroadcast();
}
测试结果:
1970-01-01 08:15:55.454 30006-30006/com.example.broadcastdemo D/HightLevelReceiver: Hight Level action:com.example.broadcastdemo.SEND_ORDER_BROADCAST
2、修改广播内容
用上面的例子继续做修改,由于前面的广播并没有内容我们用sendOrderedBroadcast方法添加内容进去’;
@Override
public void sendOrderedBroadcast(
Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
Bundle initialExtras) {
mBase.sendOrderedBroadcast(intent, receiverPermission,
resultReceiver, scheduler, initialCode,
initialData, initialExtras);
}
原API说明文档:
老师笔记中的解释:
- 第一个参数,不用说了,我们发送广播就知道了,这个是意图对象,用于封装数据和设置过滤。
- 第二个参数是权限,权限我们后面会详细说到,虽然很少用到,但是你知道这个思想,有利于你以后自己钻研android的代码。
- 第三个参数是广播接收者,这个广播接收者是最终接收的广播接收者,用于检查数据是否有传达或者数据被修改。
- 第四个参数是一个自定义的Hanlder,用于处理结果接收者,也就是上面那个接收者的回调。
- 第五个参数是初始码,这个会作为结果码,通常是Activity.RESULT_OK,也就是-1。
- 第六个参数是用于传递数据的,这个数据在各个Receiver里获取到,通过getResultData方法获取。这个其实通常为null
- 第七个参数也是用于封装数据的,不同的是,这个用于封装数据集合,从上面的代码可以知道 ,我用来封装了一个钱的数据。
在HightLevelReceiver的onReceiver的函数获取广播内容并修改内容,DefaultLevelReceiver和LowLevelReceiver同理;
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "Hight Level action:" + action);
//终止广播
//abortBroadcast();
//接收广播内容
Bundle resultExtras = getResultExtras(true);
String content = resultExtras.getCharSequence("content").toString();
Log.d(TAG, "content: " +content);
//修改广播内容
resultExtras.putCharSequence("content","我是被修改过的广播内容");
}
测试结果:
1970-01-01 08:43:41.844 11517-11517/com.example.broadcastdemo D/HightLevelReceiver: Hight Level action:com.example.broadcastdemo.SEND_ORDER_BROADCAST
1970-01-01 08:43:41.844 11517-11517/com.example.broadcastdemo D/HightLevelReceiver: content: 我是没有被修改过的广播内容
1970-01-01 08:43:41.848 11517-11517/com.example.broadcastdemo D/DefaultLevelReceiver: default level: com.example.broadcastdemo.SEND_ORDER_BROADCAST
1970-01-01 08:43:41.848 11517-11517/com.example.broadcastdemo D/DefaultLevelReceiver: content: 我是被修改过的广播内容
1970-01-01 08:43:41.850 11517-11517/com.example.broadcastdemo D/LowLevelReceiver: Low Level action:com.example.broadcastdemo.SEND_ORDER_BROADCAST
1970-01-01 08:43:41.850 11517-11517/com.example.broadcastdemo D/LowLevelReceiver: content: 我是再一次被修改过的广播内容
Android广播权限(例子七-我的广播谁可以接收?)
流程:发送者定义广播权限-发送带权限的有序广播-接收者申明广播权限
发送者定义权限:
<permission android:name="com.example.broadcastdemo.ORDER_PERMISSION"/>
发送带权限的有序广播
sendOrderedBroadcast(intent,Manifest.permission.ORDER_PERMISSION,null,null,Activity.RESULT_OK,null,bundle);
接收者申明广播权限(别忘了注册广播)
<uses-permission android:name="com.example.broadcastdemo.ORDER_PERMISSION"/>
Android广播权限(例子八-谁可以给我这个广播接收者发送广播)
流程:接收者定义广播权限-发送者申明广播权限-发送者发送广播
接收者定义广播权限(注意有两个地方添加了com.example.broadcastdemo.WHO_CAN_SEND_ME)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.broadcasepermissiondemo">
<!--<uses-permission android:name="com.example.broadcastdemo.ORDER_PERMISSION"/>-->
<permission android:name="com.example.broadcastdemo.WHO_CAN_SEND_ME"/>
<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">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".OrderBroadcastReceiver" android:permission="com.example.broadcastdemo.WHO_CAN_SEND_ME">
<intent-filter>
<action android:name="com.example.broadcastdemo.SEND_ORDER_BROADCAST"/>
</intent-filter>
</receiver>
</application>
</manifest>
发送者申明广播权限
<uses-permission android:name="com.example.broadcastdemo.WHO_CAN_SEND_ME"/>
发送者发送广播
sendOrderedBroadcast(intent,null,null,null,Activity.RESULT_OK,null,bundle);
Android广播权限-小结
1、谁定义权限(permission而不是<uses-permission),另一方必须得按照这个规则发送权限或者接收权限;
2、当发送者定义权限的时候,接收者必须得按照这个规则才可以接收到广播;
3、当接收者定义权限的时候,发送者必须得按照这个规则才可以接收者才可以接收到广播;