Broadcast和Broadcast Receiver
Broadcast和Broadcast Receiver是什么?
Broadcast发送信息,Broadcast Receiver则负责接收信息,Broadcast分为:
- 标准广播:发送的信息没有先后顺序,接收者都可收到该广播信息
- 有序广播:发送的信息有先后顺序,优先级高的接收者接收后可截断该广播,从而使后面的接收者无法继续接收
Broadcast Receiver使用
动态注册(网络监听)
- registerReceiver()注册监听需传入BroadcastReceiver和intentFilter:
- intentFilter过滤器添加需要监听的Action
- NetworkChangeReceiver为自定义广播接收器继承BroadcastReceiver,重写onReceive()处理接收到广播后的逻辑(通过ConnectivityManager中的NetworkInfo判断网络状态)
- 在onDestroy()中要取消注册
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
private class NetworkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
if (networkInfo!=null&&networkInfo.isAvailable()) {
Toast.makeText(context, "Network Available", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(context, "Network Unavailable", Toast.LENGTH_SHORT).show();
}
}
}
}
在运行前还需要再Mainfest.xml中的<manifest>标签添加权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
静态注册(开机自启动)
动态注册需要当程序启动后才能收到广播,因为注册的代码是写在onCreate()方法中的,而静态注册可以实现让程序在未启动状态下接收到广播,如接收开机广播实现应用的开机自启动。
右键点击包→New→Ohter→Broadcase Receiver,命名为BootCompleteReceiver,Exported表示是否允许接收本程序以外的广播,Enabled表示是否启动这个Broadcase Receiver,都勾选。
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Boot Complete", Toast.LENGTH_SHORT).show();
}
}
修改Mainfest.xml,添加权限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
并在<receiver>标签中添加:
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
Tips:
1.onReceiver()中不可以添加耗时操作,因为在BroadcastReceiver 中是不允许开启线程的,当onReceiver()运行较长时间还未结束就会导致程序报错。
Broadcast使用
标准广播
发送前先创建接收者MyBroadcastReceiver:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "MyBroadcastReceiver", Toast.LENGTH_SHORT).show();
}
}
在Manfest.xml中给MyBroadcastReceiver添加<intent-filter>:
<intent-filter>
<action android:name="MY_BROADCAST"/>
</intent-filter>
在activity_main.xml中添加一个按钮用于发送广播:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:text="send Broadcast"
android:layout_height="wrap_content"/>
</LinearLayout>
修改MainActivity,利用sendBroadcast()方法发送标准广播,Android8.0不能发送全局广播,需要使用intent.setPackage()指定广播的范围
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button=findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent("MY_BROADCAST");
intent.setPackage("com.example.demo0");
sendBroadcast(intent);
}
});
}
}
有序广播
创建两个广播接收者
public class FirstReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TAG", "FirstReceiver");
}
}
public class SecondReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TAG", "SecondReceiver");
}
}
添加action,通过<intent-filter>标签中的android:priority属性设置广播接收者的优先级[-1000,1000],高优先级优先接收广播
<receiver
android:name=".SecondReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="0">
<action android:name="OrderBoardTest" />
</intent-filter>
</receiver>
<receiver
android:name=".FirstReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="1000">
<action android:name="OrderBoardTest" />
</intent-filter>
</receiver>
修改MainActivity,利用sendOrderedBroadcast()即可发送有序广播,第一个参数为intent,第二个参数为权限
Intent intent = new Intent();
intent.setAction("OrderBoardTest");
intent.setPackage("com.example.demo0");
sendOrderedBroadcast(intent, null);
可看到优先级高的FirstReceiver先收到广播,若通过abortBroadcast()方法截断广播,则第二个广播接收者将无法收到广播
修改广播内容
修改有序广播代码,发送时创建Bundle传入sendOrderedBroadcast重载方法
Bundle data = new Bundle();
data.putCharSequence("content", "hello world");
sendOrderedBroadcast(intent, null, null, null, null, Activity.RESULT_OK, null, data);
在FirstReceiver的onReceiver中获取值并修改(使用intent无法修改)
public class FirstReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle resultExtras = getResultExtras(true);
String content = resultExtras.getCharSequence("content").toString();
Log.d("TAG", "FirstReceiver content: " + content);
resultExtras.putCharSequence("content", "hello Java");
setResultExtras(resultExtras);
}
}
在SecondReceiver取修改后的值
public class SecondReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle resultExtras = getResultExtras(true);
String content = resultExtras.getCharSequence("content").toString();
Log.d("TAG", "SecondReceiver content: " + content);
}
}
点击发送广播后,第一个广播中途修改了携带的信息
发送者:谁可以接收我的广播
在demo0作为发送者在Manifest申明权限
<permission android:name="com.example.demo0.PERMISSION" />
修改activity_main.xml创建按钮
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/send"
android:text="sendBroadcast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
修改MainActivity设置点击事件,发送时指定权限
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.send).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("PermissionTest");
intent.setPackage("com.example.demo1");
sendOrderedBroadcast(intent, Manifest.permission.PERMISSION);
}
});
}
}
demo1作为接收者在Manifest使用权限,这样就可以接收demo0的广播
<uses-permission android:name="com.example.demo0.PERMISSION"/>
创建接收者重写onReceive
public class PermissionTestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TAG", "onReceive: action:" + intent.getAction());
}
}
在Manifest指定action
<receiver
android:name=".PermissionTestReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="PermissionTest"/>
</intent-filter>
</receiver>
接收者:谁可以给我发送广播
demo1作为接收者在Manifest中声明权限
<permission android:name="com.example.demo1.WHO_CAN_SEND2ME" />
创建接收者
public class PermissionTestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TAG", "onReceive: action:" + intent.getAction());
}
}
为接收者指定action和permission
<receiver
android:name=".PermissionTestReceiver"
android:enabled="true"
android:exported="true"
android:permission="com.example.demo1.WHO_CAN_SEND2ME">
<intent-filter>
<action android:name="PermissionTest" />
</intent-filter>
</receiver>
demo0作为发送者,使用权限,这样才能向demo1发送广播
<uses-permission android:name="com.example.demo1.WHO_CAN_SEND2ME"/>
发送广播指定demo1中接收者的action
Intent intent = new Intent();
intent.setAction("PermissionTest");
intent.setPackage("com.example.demo1");
sendOrderedBroadcast(intent, null);
本地广播
上面发送的广播属于全局广播,即发出的广播允许被其他应用程序接收,不够安全,数据可能被其他接收者截获。而本地广播只能够在应用程序内部进行传递。
添加依赖
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
发送和接收:
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
localBroadcastManager = LocalBroadcastManager.getInstance(this);
Button button = findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("localBroadcast");
localBroadcastManager.sendBroadcast(intent);
}
});
intentFilter = new IntentFilter();
intentFilter.addAction("localBroadcast");
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver);
}
class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "LocalReceiver", Toast.LENGTH_SHORT).show();
}
}
}