学习资料
简介
- Broadcast是android中的四大组件之一(其他的组件分别是:Activity,Content provider,Service),是在组件之间传播数据(Intent)的一种机制。广播的发送者和接收者事先是不需要知道对方的存在的。这样带来的好处便是,系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。
广播具有以下特性
- 广播接收者的生命周期是非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁
- 广播接收者中不要做一些耗时的工作,否则会弹出Application No Response错误对话框
- 最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉,耗时的较长的工作最好放在服务中完成
广播的分类
- 广播分为系统广播和本地广播,系统广播可以分为标准和有序
- 标准广播:一但发出所有接收者同时受到
- 有序广播:接收者按优先级受到而且可以截断
- 本地广播:以上都是系统全局广播,发出的广播可以被其他任何应用接收这样容易产生安全问题,所以有了本地广播只能在应用程序内部传递。
简单使用
- 不要想的太难,举一个简单的例子吧:你如果手机要看番,那必须得上网吧,手机由没上网的状态到上网的状态,这种变化会发出的就是一种广播,我们想要接收这个广播就需要一个广播接收器,而获得广播接收器就需要自己注册,一共有2种注册方法,分别为动态注册和静态注册(如果是在没办法理解广播的定义的话,你就把它当作一个全局监听器,用来实现不同组件的信息传递)
动态注册
- 动态注册是在代码中注册的,根据广播的一个特性广播接收者的生命周期是非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁
- 我们可以知道广播接收后一定要销毁,可是动态注册并不能自动销毁,所以,动态注册后一定要自己添加销毁的程序
实现广播接收器BroadcastReceiver
- 广播接收器主要就是重写onReceive方法,这里最好时做简单的处理,不要做任何耗时的操作。
/**
* 简单的广播接收器
*/
public class MyFirstBroadCast extends BroadcastReceiver {
private final String TAG = "MyFirstBroadCastTAG";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "接收到广播");
String info = intent.getStringExtra("key");
Log.d(TAG, "广播内容:" + info);
}
}
- 动态注册,代码动态注册需要记得再页面销毁的时候取消注册。
/**
* 动态注册广播
* 这个需要再销毁页面的时候取消注册
*/
MyFirstBroadCast firstBroadCast;
private void initReceiver() {
firstBroadCast = new MyFirstBroadCast();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("simple broadcast");
registerReceiver(firstBroadCast, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (null != firstBroadCast)
unregisterReceiver(firstBroadCast);
}
- 发送广播
@Override
public void initButton() {
super.initButton();
initButton(R.id.btn_send, new View.OnClickListener() {
@Override
public void onClick(View v) {
sendBroadCast();
}
});
}
/**
* 发送广播
*/
private void sendBroadCast() {
Intent intent = new Intent("simple broadcast");
intent.putExtra("key", "这是一条简单的广播");
sendBroadcast(intent);
}
-
简单运行,结果正确
图片.png
静态注册
- 使用流程一样,知识区别点就是广播需要再manifest文件注册,过滤器也是再里面添加;
- 注意一个事情,高版本的API(比如我用的API29,安卓8以上就用不了了)就已经没有静态注册了
- 关于上面的,验证了下,确实高版本再manifest中注册的接收器,在发送广播后确实没有接收到消息。
- 针对上面的情况,你的广播瘾犯了就是想用静态注册怎么办呢,Android8.0 静态receiver接收不到隐式广播这篇文章帮你解决了,我试了下,很好用。
<receiver
android:name=".fourassembly.broadcast.MyFirstBroadCast"
android:exported="true">
<intent-filter>
<action android:name="simple broadcast"/>
</intent-filter>
</receiver>
- 高版本下使用静态注册,在发送广播的时候加上package
/**
* 发送广播
*/
private void sendBroadCast() {
Intent intent = new Intent("simple broadcast");
intent.putExtra("key", "这是一条简单的广播");
intent.setPackage(getPackageName());//针对高版本静态注册的广播需要添加的内容,要不然无法接收到相应的广播
sendBroadcast(intent);
}
- 能正常接收到广播哈。
广播分类
- Android的广播主要分为2种,一种是标准广播,一种是有序广播,其中标准广播发出后,所有广播接收器几乎同时接收到这条广播消息,并且不能被截断
而有序广播同一时刻只有一个广播接收器会收到这条广播,并且可以被截断
标准广播
- 我们上面发送的广播就是标准广播。
- 8.0后广播在AndroidManifest.xml中注册后发送intent是接收不到广播了,看了一下原因,好像是8.0为了管理系统和节约电量特别针对广播和服务发送intent的方式启动做出的改变,也就是说广播和服务不能随意收intent了,要对广播和服务更精确的指向,所以在创建intent的时候,我们需要指定我们的广播和服务的包名加类名,为的就是精确
- 资料说 intent.setComponent()后可以使用静态广播。但是我尝试了下,怎么都没成功,不知道是不是现在Android相关的改了。同时我尝试了另一个方法就是设置flag
//以下设置失败了
intent.setComponent(new ComponentName("com.southwind.androidfoundation.fourassembly.broadcast"
,"com.southwind.androidfoundation.fourassembly.broadcast.MyFirstBroadCast"));
//以下两种设置成功了
intent.setPackage(getPackageName());
int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
intent.addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND);
- 完整设置,静态注册的广播下面两种设置人选其一就可以完成发送和接受。但是上面的那种没成功,不知道是我哪里写的有问题,别人资料是成功了的。
/**
* 发送广播
*/
@SuppressLint("WrongConstant")
private void sendBroadCast() {
Intent intent = new Intent("simple broadcast");
intent.putExtra("key", "这是一条简单的广播");
// intent.setPackage(getPackageName());//针对高版本静态注册的广播需要添加的内容,要不然无法接收到相应的广播
//第二种解决方法,传入精确的地址,即使用精确的广播接受位置 第一个参数时包名,第二个参数是类名(需要包含包名)
// intent.setComponent(new ComponentName("com.southwind.androidfoundation.fourassembly.broadcast"
// ,"com.southwind.androidfoundation.fourassembly.broadcast.MyFirstBroadCast"));
int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
intent.addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND);
sendBroadcast(intent);
}
有序广播
- 前面的步骤和标准广播一样,注意有序广播的特点:同一时刻只有一个广播接收器会收到这条广播,并且可以被截断
- 将有序广播种的sendBoardcast改成sendOrderedBroadcast(intent,null)
- 再写一个广播接收器
public class MySecondBroadCast extends BroadcastReceiver {
private final String TAG = "MySecondBroadCastTAG";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "第二个广播接收器,接收到广播");
String info = intent.getStringExtra("key");
Log.d(TAG, "广播内容:" + info);
}
}
- 设置广播优先级,MyFirstBroadCast设置为100,MySecondBroadCast设置为50
<receiver
android:name=".fourassembly.broadcast.MyFirstBroadCast"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="simple broadcast"/>
</intent-filter>
</receiver>
<receiver
android:exported="true"
android:name=".fourassembly.broadcast.MySecondBroadCast">
<intent-filter android:priority="50">
<action android:name="simple broadcast"/>
</intent-filter>
</receiver>
- 首先我们设置截取广播
private final String TAG = "MyFirstBroadCastTAG";
@Override
public void onReceive(Context context, Intent intent) {
//这个方法表示将截取广播,不会继续向后传递
abortBroadcast();
Log.d(TAG, "第一个广播接收器,接收到广播");
String info = intent.getStringExtra("key");
Log.d(TAG, "广播内容:" + info);
}
}
- 发送广播,有序广播调用的方法不同endOrderedBroadcast(intent,null)方法
/**
* 发送广播
*/
@SuppressLint("WrongConstant")
private void sendBroadCast() {
Intent intent = new Intent("simple broadcast");
intent.putExtra("key", "这是一条简单的广播");
// intent.setPackage(getPackageName());//针对高版本静态注册的广播需要添加的内容,要不然无法接收到相应的广播
//第二种解决方法,传入精确的地址,即使用精确的广播接受位置 第一个参数时包名,第二个参数是类名(需要包含包名)
// intent.setComponent(new ComponentName("com.southwind.androidfoundation.fourassembly.broadcast"
// ,"com.southwind.androidfoundation.fourassembly.broadcast.MyFirstBroadCast"));
int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
intent.addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND);
sendOrderedBroadcast(intent,null);
}
-
有截取广播的运行结果
图片.png
-
去掉截取广播的运行结果
图片.png
- 从新设置优先级后的结果,这次MyFirstBroadCast优先级为10,MySecondBroadCast优先级为20
<receiver
android:name=".fourassembly.broadcast.MyFirstBroadCast"
android:exported="true">
<intent-filter android:priority="10">
<action android:name="simple broadcast"/>
</intent-filter>
</receiver>
<receiver
android:exported="true"
android:name=".fourassembly.broadcast.MySecondBroadCast">
<intent-filter android:priority="50">
<action android:name="simple broadcast"/>
</intent-filter>
</receiver>
图片.png
- 上图说明了,有序广播的发送顺序是按照设置的有限级返送的,优先级高的优先发送,如果不截取广播,继续向后发送。
本地广播
- 以上的广播都是全局的,可以被任何程序接受,就不辣么安全,这位开发者,你也不想自己的广播被别人接受是吧!!!而本地广播,只能在自己的app内发送和接收。
- 本地广播只能动态注册不能静态注册
- 注册本地广播
/**
* 注册本地广播接收器
*/
private void initLocalReceiver() {
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
MySecondBroadCast broadCast = new MySecondBroadCast();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("simple broadcast");
manager.registerReceiver(broadCast,intentFilter);
}
- 发送本地广播
/**
* 发送本地广播
*/
private void sendLocalBroadCast(){
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
Intent intent = new Intent("simple broadcast");
intent.putExtra("key", "这是一条本地广播");
manager.sendBroadcast(intent);
}
-
运行结果
图片.png
常用的系统广播
- 这些广播是手机系统发送的我们只需要接收就行
- 即在广播接收器添加响应的action即可
监听网络变化 android.net.conn.CONNECTIVITY_CHANGE
关闭或打开飞行模式 Intent.ACTION_AIRPLANE_MODE_CHANGED
充电时或电量发生变化 Intent.ACTION_BATTERY_CHANGED
电池电量低 Intent.ACTION_BATTERY_LOW
电池电量充足(即从电量低变化到饱满时会发出广播) Intent.ACTION_BATTERY_OKAY
系统启动完成后(仅广播一次) Intent.ACTION_BOOT_COMPLETED
按下照相时的拍照按键(硬件按键)时 Intent.ACTION_CAMERA_BUTTON
屏幕锁屏 Intent.ACTION_CLOSE_SYSTEM_DIALOGS
插入耳机时 Intent.ACTION_HEADSET_PLUG
未正确移除SD卡但已取出来时(正确移除方法:设置-SD卡和设备内存-卸载SD卡) Intent.ACTION_MEDIA_BAD_REMOVAL
成功安装apk Intent.ACTION_PACKAGE_ADDED
成功删除apk Intent.ACTION_PACKAGE_REMOVED
重启设备 Intnet.ACTION_REBOOT
屏幕被关闭 Intent.ACTION_SCREEN_OFF
屏幕被打开 Intent.ACTION_SCREEN_ON
- 我在我的接收器中添加一个屏幕关闭的广播action
<receiver
android:name=".fourassembly.broadcast.MyFirstBroadCast"
android:exported="true">
<intent-filter android:priority="10">
<action android:name="simple broadcast" />
<action android:name="android.intent.action.SCREEN_OFF" />
</intent-filter>
</receiver>
- 上面的示例大失败,好像这种系统的广播无法通过静态注册来监听哈。
- 转头就动态注册了下
private void initReceiver() {
firstBroadCast = new MyFirstBroadCast();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("simple broadcast");
intentFilter.addAction(Intent.ACTION_SCREEN_ON);//屏幕开启
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);//屏幕关闭
registerReceiver(firstBroadCast, intentFilter);
}
-
运行结果如下,在开关屏幕的时候确实接收到了广播,但是不知道具体内容
图片.png
-
我反手就是要给调试,让我康康intent的内容~~啊,没什么特别的内容,就一个action比较清晰,所以真要监听不同的系统广播还是分别写广播接收器分别监听吧。
图片.png












网友评论