安卓里面的广播是非常灵活的,每一个应用程序可以对自己喜欢的广播进行订阅,来得到广播的数据。
这些广播可能来自系统,也可能来自于其他的应用程序。
- 广播分为标准广播和有序广播
标准广播就是发出一条广播的时候,所有的广播接收者几乎是同一时间接收到这个广播的消息。
有序广播就是发出一条广播的时候,各个接受者依次接收到我们的这个广播。
安卓系统里面内置了很多系统级别的广播,比如:当手机开机完成以后就会发出一条广播,电量变化的时候会发出一条广播,时间的改变也会发出一条广播。。。。。。
安卓的广播也分为静态广播和动态广播。动态广播的大部分代码都是在java文件里面写的,静态广播大部分的代码是在manifest文件里面写的。
- 需要注意的是不要在onReceived() 方法里面添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中是不允许开启线程的,当onReceived()方法运行了较长时间而没有结束的时候,程序就会报错。
1 简单的一个广播案例
当检测到网络连接发生变化的时候就弹出一个提示框。
代码的书写过程。
因为我们要检测网络状态,所以需要配置网络变化的权限。在清单文件里面加上这个权限代码
/*
写一个网络变化的广播的接收器,当网络变化的时候弹出一条提示
实现的过程。
1. 写一个广播的接收器 其实就是写一个类,继承Boradcast,在类里面重写onReceive方法在,在方法里面
2. 创建一个广播的过滤器,其实就是指定一下我的广播接收器要收到那个或者那些 广播的数据
3. 通过registerReceiver 是一个系统的方法, 将我的广播接收器和广播的过滤器结合起来,正式接收广播
4. 在onDestroy方法里面使用 unregisterReceiver(myNetWorkChangeReceiver); 取消掉我的广播接收器
/
代码:
public class MainActivity extends AppCompatActivity {
/**
* 写一个网络变化的广播的接收器,当网络变化的时候弹出一条提示
* 实现的过程。
* 1. 写一个广播的接收器 其实就是写一个类,继承Boradcast,在类里面重写onReceive方法在,在方法里面
* 2. 创建一个广播的过滤器,其实就是指定一下我的广播接收器要收到那个或者那些 广播的数据
* 3. 通过registerReceiver 是一个系统的方法, 将我的广播接收器和广播的过滤器结合起来,正式接收广播
* 4. 在onDestroy方法里面使用 unregisterReceiver(myNetWorkChangeReceiver); 取消掉我的广播接收器
*/
private IntentFilter intentFilter ; //广播的过滤器,其实就是你想收到按个广播的消息
private MyNetWorkChangeReceiver myNetWorkChangeReceiver ; //我自己定义的一个广播的接收处理类
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter() ; //广播的过滤器
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); //指定我想过滤谁其实就是我想收到那些广播
//找到我定义的广播接收器
myNetWorkChangeReceiver = new MyNetWorkChangeReceiver();
//给我的广播接收器绑定 过滤器,其实就是指定接收器要接收那个广播 registerReceiver 是一个系统的方法,
registerReceiver(myNetWorkChangeReceiver,intentFilter); //真正的让我的广播接收器开始工作
}
//写一个接收广播的内部类,在里面对接受的的广播数据进行处理
class MyNetWorkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//Toast.makeText(context , "网络状态改变了",Toast.LENGTH_SHORT).show();
//当网络变化以后,我们检测一下当前的网络是否可以用
//getSystemService这是一个系统的服务类
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
//你要拿到网络状态,需要有 拿到网络状态的权限
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isAvailable()){
Toast.makeText(context , "网络状态改变了,网络可用",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(context , "网络状态改变了,网络不可用",Toast.LENGTH_SHORT).show();
}
}
}
//再退出软件的时候需要取消对广播的接收
//onDestroy 方法的执行当我们关闭软件,或者按返回键回到桌面的时候就会
//执行onDestroy方法,但是按home回到桌面的时候不会执行Ondestroy方法
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(myNetWorkChangeReceiver);
}
}
2 静态广播实现
上面那个广播是在java文件里面写的,好处就是我们可以使用 unregisterReceiver(myNetWorkChangeReceiver)随时关闭对广播的接收。但是缺点就是我们一定要打开软件才可以接收到广播。
现在我们创建一个静态广播开机
- 先创建一个广播类
起个类名,写一下代码
public class BootCompleteReceiver extends BroadcastReceiver {
/**
* 这是我自己创建的一个广播接收类
* 使用快捷方式创建的话,这个广播接收器 会在清单文件里面注册
*/
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Toast.makeText(context, "开机完成", Toast.LENGTH_LONG).show();
}
}
使用快捷键创建一个广播接收类的好处就是,自动的会在manifest文件里面添加我们的广播接收器,这是静态广播必须要实现的一步。
我们看一下manifest文件里面
可以看到确实在清单文件里面添加了一个
- 2 创建了广播接收器以后,我们就要给广播接收器添加一个过滤器了,其实就是告诉广播接收器需要接收那些广播了。在manifest文件里面的
标签里面添加广播的过滤器。
- 3 监听开机广播也是需要权限的,我们需要在manifest文件里面添加下面的权限。
这样一个静态广播就做好了,关闭android studio的模拟器在打开之后就会弹出“开机完成”这个toast了。
但是我的模拟器只看到了一次这样的效果,其实就是失败了。嘿嘿,但是静态广播的流程就是这样的。
3 发送自定义的一个广播
前面我们已经说过广播分为两种方式:标准的广播和有序广播,标准的广播就是其他广播接收者几乎是同一时间接收到消息的;由于的广播就是广播的接收者是按照顺序接受到广播的数据的。
3.1 发送标准的广播(静态注册)
标注广播,接收者几乎同一时间接收到消息。
- 首先我们还是要先创建一个广播的接收器
新建一个广播类MyBroadcastReceiver
- 2 在manifest文件里注册一下我写的广播接收器,并且为广播接收器设置一个过滤器(指定接收那些广播),
在manifest文件里面写了广播的过滤器,这样其实是静态注册广播。
这里指定的就是一个我自己定义的一个叫做MY_BROADCAST的广播。其实就是指定MyBroadcastReceiver接收名字叫做MY_BROADCAST的广播
- 接收的工作就做好了,这里开始点击一个按钮发送一个广播
在主活动里面设置一个按钮,点击按钮发送一个广播,这样MyBroadcast方法收到广播消息之后就会弹出一个toast了。
点击发送广播的代码,但是这样发送广播以后,广播的接收器其实是并没有接收到数据的。
出现的问题:点击按钮发送了一个广播,但是接收器却没有接收到数据。这是为啥??????
经过百度以后发现是因为Android 8.0 以后在发送广播的时候需要指定广播的作用范围,
具体android8.0 对于静态广播的限制可以看这里。https://blog.csdn.net/weixin_33817046/article/details/117300546
- 解决方法就是在发送广播的地方添加一行代码
这样就就可发送并接受简单地自定义广播了。
- 需要注意的是:
我们可以看到发送广播的时候使用的是intent对象来发送的,这时候我们就会想到intent还可以携带其他的参数啊
,就是使用intent.putExtra(key,value); 这样通过intent传递一个消息过去。
在接收端我们拿到intent里面送过来的其他数据
可以看到接收到广播了,而且拿到了广播里面的数据了
3.2 发送标准的广播(动态注册)
3.1 里面我发现使用静态注册的时候,在android8.0以后有限制,所以这这里我就直接使用动态注册了。
动态注册的时候需要注意的是我们,一般是在oncreat方法里面进行注册,在onDestroy方法里面取消注册
自定义 的一个接收器类。
public class MyReceiver2 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String extra = intent.getExtras().getString("extra");
Toast.makeText(context, "222收到广播的数据了,收到额外的数据是:"+extra, Toast.LENGTH_SHORT).show();
}
}
点击按钮发送广播,并且在这里面进行接收器的动态注册,取消注册
public class MainActivity extends AppCompatActivity {
private MyReceiver myReceiver = new MyReceiver();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//动态注册一个广播接收器
//广播的过滤器
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.standordbroadcast.MY_BROADCAST");
//动态注册广播接收器
registerReceiver(myReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
//退出的时候取消广播的注册
unregisterReceiver(myReceiver);
}
}
3.3 一程序接收到另一程序的广播
前面我们提到了,广播是可以跨进程的,意思就是说我们发送一条广播,只要别的软件注册了这个广播,那么别的软件都是可以拿到广播里面的数据的。
[x] 1. 我在新建一个软件,使用动态注册广播接收器
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String extra = intent.getExtras().getString("extra");
Toast.makeText(context, "3333收到广播的数据了,收到额外的数据是:"+extra, Toast.LENGTH_SHORT).show();
}
}
[x] 在manifest文件里面静态注册广播,主界面 ```java public class MainActivity extends AppCompatActivity {
private MyReceiver myReceiver = new MyReceiver();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//动态注册一个广播接收器
//广播的过滤器
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.standordbroadcast.MY_BROADCAST");
//动态注册广播接收器
registerReceiver(myReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
//退出的时候取消广播的注册
unregisterReceiver(myReceiver);
}
}
- [x] 效果 点击按钮以后两个程序都弹出了提示框,注意因为我们吧取消注册的方法写在了onDestroy方法里面,所以不要按返回键,按了返回键,就执行了onDestroy方法就取消广播的注册了,要使用home键返回桌面,
![image.png](https://cdn.nlark.com/yuque/0/2022/png/1791947/1651474573781-9d2e36a7-9c2a-49b3-859f-f016e3f959f8.png#clientId=u49adb180-86e5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=72&id=u4bd9b990&margin=%5Bobject%20Object%5D&name=image.png&originHeight=298&originWidth=705&originalType=binary&ratio=1&rotation=0&showTitle=false&size=18148&status=done&style=none&taskId=u0eb1eccf-d4f9-42ac-80f9-420d4e3fff2&title=&width=171)![image.png](https://cdn.nlark.com/yuque/0/2022/png/1791947/1651474594190-89a8448f-e7ed-4451-8ac6-6777f359bf11.png#clientId=u49adb180-86e5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=126&id=u15d38097&margin=%5Bobject%20Object%5D&name=image.png&originHeight=361&originWidth=599&originalType=binary&ratio=1&rotation=0&showTitle=false&size=26978&status=done&style=none&taskId=u9155673d-4e80-4cec-ba17-117be2a3373&title=&width=209.4666748046875)![image.png](https://cdn.nlark.com/yuque/0/2022/png/1791947/1651474620961-775f5614-cb4d-4e26-b741-523f24817e29.png#clientId=u49adb180-86e5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=69&id=u4f719092&margin=%5Bobject%20Object%5D&name=image.png&originHeight=223&originWidth=615&originalType=binary&ratio=1&rotation=0&showTitle=false&size=22007&status=done&style=none&taskId=u1a432317-5989-48b4-bc26-18e46daf04c&title=&width=190.00001525878906)
<a name="qCOwf"></a>
## 3.4 发送有序广播
我们在3.1 3.2 进行了广播的发送,发送的广播都是标准的广播,其他的程序几乎是同时拿到广播的数据的。<br />现在我们想发送有序广播,让其他的程序依次拿到广播里面的数据。<br />3.1 3.2 里面发送广播的时候使用的就是sendBroadcast这个方法,发送的是标准的广播,其实发送有序广播使用的就是sendOrderBroadCast()方法。<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1791947/1651474944591-a8d0d564-3d5a-47ee-a3ec-5384aff7baed.png#clientId=u49adb180-86e5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=111&id=u05eb207a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=208&originWidth=1213&originalType=binary&ratio=1&rotation=0&showTitle=false&size=49585&status=done&style=none&taskId=u07077e20-c1ef-4165-9f7e-29cec8c7a44&title=&width=646.9333333333333)
点击按钮发送一个有序广播<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1791947/1651475220444-bc67eb83-c4af-49be-b82e-5593d6171fe1.png#clientId=u49adb180-86e5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=295&id=ua26607c6&margin=%5Bobject%20Object%5D&name=image.png&originHeight=553&originWidth=1350&originalType=binary&ratio=1&rotation=0&showTitle=false&size=122267&status=done&style=none&taskId=u30791369-3c50-4c6c-95f7-83ffaaf978b&title=&width=720)
- [x] 有序广播就牵扯到排序的问题,就是要指定接收器的优先级,其实就是给intentFilter设置一个优先级就好了
![image.png](https://cdn.nlark.com/yuque/0/2022/png/1791947/1651475470396-03be8b77-25b4-430e-98ef-c8920e5f2d03.png#clientId=u49adb180-86e5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=154&id=u0c7688a7&margin=%5Bobject%20Object%5D&name=image.png&originHeight=288&originWidth=1210&originalType=binary&ratio=1&rotation=0&showTitle=false&size=63507&status=done&style=none&taskId=uba43cd6d-fef7-45df-a3f7-ac21b38f7fc&title=&width=645.3333333333334)<br />好了这个时候有序广播就已近OK了
<a name="rlm4a"></a>
# 4 使用本地广播
本地广播的意思就是广播只会在我们这个程序里面广播,别的程序是拿不到我们广播的数据得。不用担心自己数据的安全问题。<br />需要注意的是本地广播是没有办法使用静态注册来实现接收的。<br />本地广播的用法也简单,主要就是使用一个LocalBroadCastManager来对广播进行管理,并且提供了发送广播和接收广播接收器的方法
和以前广播的、注册广播、取消注册、发送广播 。相比:
- [x] 以前注册广播的时候使用的方法registerReceiver(广播接收器),现在使用的是localBroadcastManager.registerReceiver(广播接收器);
- [x] 以前取消注册广播的时候使用的方法是:unregisterReceiver(广播接收器); 现在使用的是
localBroadcastManager.unregisterReceiver(myReceiver2);
- [x] 以前发送广播的时候使用的方法是sendBroadcast(intent) ,现在是
localBroadcastManager.sendBroadcast(intent);
广播接收器的代码
```java
public class MyReceiver2 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String extra = intent.getExtras().getString("extra");
Toast.makeText(context, "222收到广播的数据了,收到额外的数据是:"+extra, Toast.LENGTH_SHORT).show();
}
}
发送广播,注册广播接收器,取消广播接收器 的代码
public class MainActivity extends AppCompatActivity {
//我自己的广播接收器
private MyReceiver2 myReceiver2 = new MyReceiver2() ;
private IntentFilter intentFilter ;
private LocalBroadcastManager localBroadcastManager ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获得本地广播管理器的实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//我这里使用动态注册广播
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.standordbroadcast.MY_BROADCAST");
//给过滤器设置一个优先级 我这里设置为100 ,保证我较快的接收到广播
intentFilter.setPriority(100);
//使用本地广播注册器 注册广播,接收器
localBroadcastManager.registerReceiver(myReceiver2,intentFilter);
Button button = findViewById(R.id.Send_broadcast);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送一个名字叫做MY_BROADCAST的广播
Intent intent = new Intent("com.example.standordbroadcast.MY_BROADCAST");
//intent.setPackage(getPackageName()); 静态注册广播接收器的话 这里需要加一句这个
intent.putExtra("extra","多带一个信息");
//发送本地广播
localBroadcastManager.sendBroadcast(intent);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//unregisterReceiver(myReceiver2); 以前的取消注册广播接收器的方法
//使用本地广播接收器取消广播接收器
localBroadcastManager.unregisterReceiver(myReceiver2);
}
}