一:什么是广播?
中学时代,学校有什么重要通知,一般就会通过广播告知全校师生。
为了便于进行系统级别的消息通知,Android也引入了一套类似于广播的消息机制
结尾有几个注意问题
广播大致分为两类:
1.标准广播:
这是一种完全异步的广播,在广播发出之后,所有的广播接收器,几乎会在同一时间接收到这条消息,因此它们之间没有一种先后顺序。
异步:指的是程序运行时,某个操作可以不阻塞主程序执行的情况下进行。异步操作中,程序可以继续执行其他任务,而无需等待。异步是一种编程方式。
2.有序广播:
这是一种同步执行的广播,在广播发出之后,同一时刻,只会有一个广播接收器能够接收到这条广播消息,当这个广播接收器中的而逻辑执行完毕之后,广播才会继续传递,并且前面的广播还可以截断正在传递的广播,这样后面的广播无法接收到广播的信息了。
同步:指的是程序运行时,执行完某个操作后,才能执行另一个操作,严格按照执行顺序执行。同步操作是可以预测的。
二:为什么需要广播?
安卓(Android)系统中引入广播(Broadcast)机制的主要目的是为了实现应用程序间的通信、事件传递和事件通知,以及在应用程序内部实现模块之间的松散耦合。以下是安卓需要广播的一些主要原因:
-
应用程序通信: 在安卓系统中,不同的应用程序可能需要相互通信,共享信息或进行协作。广播机制允许应用程序发送广播消息,其他应用程序可以注册接收者并在事件发生时做出响应。这种通信方式可以帮助应用程序之间实现协同工作和信息交换。
-
系统事件通知: 安卓系统本身会产生一系列事件,如设备启动、网络状态变化、屏幕解锁、电量变化等。这些事件可能对多个应用程序具有影响。通过广播机制,系统可以在事件发生时发送广播消息,使得应用程序能够监听并做出相应的操作。
-
松散耦合: 广播机制实现了发送者和接收者之间的松散耦合。发送者无需知道接收者的详细信息,反之亦然。这使得应用程序能够独立开发,而不需要紧密耦合在一起。这在大型应用程序和模块化开发中尤其有用。
-
事件传递: 应用程序内部的不同模块可能需要进行事件传递,而不直接依赖于函数调用或变量共享。广播机制提供了一种异步事件传递的方式,允许一个模块发送事件,而其他模块可以注册接收者并对事件进行响应。
-
系统扩展: 安卓系统的各个部分可能会在不同的时间点进行更新和扩展。通过使用广播,新的功能可以通过发送广播消息来通知其他模块,而不需要直接修改现有代码。
三:广播的如何使用?
关于广播的使用我么们分为两大部分:
1.接收广播:
接收系统广播,使用意图过滤器,写明接收哪一个系统应用的通知:
无论是接收系统广播还是接收自己发送的自定义广播,我们都需要注册一个广播接收器:
如何注册广播接收器?
>动态注册:
使用java代码注册:
此处的例子是使用了一个检测网络状态的广播接收器
package com.example.activitytest;
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.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity2 extends AppCompatActivity {
private NetworkChangeReceive networkChangeReceive;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity2);
//创建意图过滤器
IntentFilter intentFilter = new IntentFilter();
//此处是接收网络变化信息
intentFilter.addAction("android.net.com.CONNECTIVITY_CHANGE");
//上一行代码就相当于,在Manifest文件里面的
/*
<intent-filter>
<action android:...
<intent-filter>
*/
networkChangeReceive = new NetworkChangeReceive();
registerReceiver(networkChangeReceive, intentFilter);
}
class NetworkChangeReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//只要网络状态发生变化,就会执行onReceive方法
Toast.makeText(MainActivity2.this, "network changed", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//记得关闭广播,不然,只要进程在运行就会,一直通知
unregisterReceiver(networkChangeReceive);
}
}
①创建意图过滤器。
②创建一个类继承BroadcastReceiver类,实现onReceive方法。创建该类的实例
③注册一个Receiver,需要两个参数:第一个:继承BroadcastReceiver类的实例,第二个意图过滤器。
注意:
其中意图过滤器中addAction方法是选择想要接收的信息,意思就是说,你想要接收什么信息,就在这里写,就可以了
为什么要使用意图过滤器:
因为安卓系统在运行过程中会一直产生各种事件和消息,例如设备启动,网络变化,电量变化,屏幕解锁等,这些事情可能对应用程序产生影响,因此安卓系统通过广播机制发送这些消息。
对于这个例子:如果想要告诉用户,网络到底是连接了还是没有连接,可以使用以下方法:
通过getSystemService();得到一个系统服务类ConnectivityManager的实例,通过这个实例的静态方法getActiveNetworkInfo();如果networkInfo不为空则,可以给一条Toast说明网络并没有问题
将onReceive方法修改之后:
//只要网络状态发生变化,就会执行onReceive方法
ConnectivityManager systemService = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = systemService.getActiveNetworkInfo();
if (networkInfo != null) {
Toast.makeText(context, "network available", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "network unavailable", Toast.LENGTH_SHORT).show();
}
>静态注册:
因为广播是安卓四大组件之一,所以可以在Manifeast.xml文件里面直接注册,也就是在代码执行之前就完成了注册
既然已经有了动态注册为什么需要静态注册呢?
因为在系统开机的时候,也需要广播使整个手机知道手机已经开机,开始工作,所有必须有一个当程序还没有运行的时候给程序消息提醒,让其开始运行。
①直接创建一个广播
②在Manifest文件里面做一些修改,说明广播接收器,接收的是什么信息。
此处是开机广播,将手机开机,此程序就会收到开机广播,当然,如果你想要进行一些操作,就可以在创建的接收器里面的onReceive方法里面进行操作。
2.发送广播:
使用意图发送自定义的广播消息:
前面我们说了,广播分为两种,分别是标准广播和有序广播,所有这里也分两类:
>标准广播:
这里我们定义一个按钮作为广播的发送键,并使用静态注册的方法:
在xml中:
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
action android:name="com.example.activitytest.MyReceiver"/>
</intent-filter>
</receiver>
在 广播接收器中:
package com.example.activitytest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "things gonna be all right", Toast.LENGTH_SHORT).show();
}
}
在活动中:
package com.example.activitytest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
btn = findViewById(R.id.button_1);
btn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//使用意图发送广播
Intent intent = new Intent("com.example.activitytest.MyReceiver");
sendBroadcast(intent);
}
}
>有序广播
发送有序广播其实很简单,只需要简单改动活动中的代码;
package com.example.activitytest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
btn = findViewById(R.id.button_1);
btn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//使用意图发送广播
Intent intent = new Intent("com.example.activitytest.MyReceiver");
//修改过后
sendOrderedBroadcast(intent,null);
}
}
只需要将此行修改为有序即可
如何截断有序广播?
只需要在onReceive方法后面加上一句
abortBroadcast()即可
如何设置广播的优先级?
在xml文件中修改为
<receiver android:name=".MyReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="100"> <action android:name="com.example.activitytest.MyReceiver"/> </intent-filter> </receiver>
补充:3.使用本地广播:
注意此处有一个类叫做LocalBroadcastManager类,不过已经被弃用了,只需要将xml
文件中的exported属性修改为false即可
对自定义广播的理解:
我们通过某个行为的发生,发送广播,在意图的构造器中写上一个包名,当作自己按钮的上的标签,如果有监听此包名的广播接收器,就会收到消息,具体是什么消息,由于使用意图,所以消息数据等由你决定,如果没有,那么就是默认,也就是啥都没有,接收器只感觉自己被戳了一下,就开始执行onReceive方法了。
如何传输数据?
使用bundle,添加到intent中,然后send出去
关于文中“标签的具体含义”:
在Android中发送广播时,通过
Intent
对象指定的"action"字符串(通常是包含包名的字符串)并不代表实际的应用包名,而是一个广播的标识符或动作名。这样的字符串命名常用于区分和标识广播的类型或动作。使用包名前缀的好处是,它确保广播动作是全局唯一的,避免与其他应用或系统广播冲突。考虑到Android平台上有成千上万的应用,使用包名前缀是一种确保唯一性的普遍做法。
举个例子,如果你的应用的包名是
com.example.myapp
,你可能为某个自定义广播定义一个动作字符串,如com.example.myapp.CUSTOM_ACTION
。这里的com.example.myapp.CUSTOM_ACTION
只是一个字符串,用于标识你的广播动作,它不表示应用的包名或其他内容。当其他组件或应用想要接收这个广播时,它们需要使用相同的字符串(
com.example.myapp.CUSTOM_ACTION
)来注册广播接收器。总的来说,广播中的这种字符串(通常建议使用包名前缀)主要用于确保广播动作的唯一性,避免混淆和冲突。