目录
一、广播机制简介
发送广播:Intent
接收广播:广播接收器(Broadcast Receiver)
Android广播分为两种类型:标准广播和有序广播
标准广播:异步执行的广播,所有的广播接收器会在同一时刻接收到的广播
有序广播:同步执行的广播,优先级高的广播接收器先收到广播,并且可以截断广播
二、接收系统广播
注册广播的方式有两种:在代码中注册(动态注册)和在AndroidManifest.xml中注册(静态注册)
1.动态注册监听网络变化
缺点:必须要在程序启动之后才能接收到广播
- 创建IntentFilter实例,并且使用addAction()方法添加想要监听的广播
- 创建一个xx类继承BroadcastReceiver,重写onReceiver()方法,然后在MainActivity创建该类的实例
- 调用registerReceiver(),传入这两个实例
- 取消注册是在onDestroy()方法中通过调用unregisterReceiver()方法来实现
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是注册广播接收器,是ContextWrapper类的方法
registerReceiver(networkChangeReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
class NetworkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "网络发生变化", Toast.LENGTH_SHORT).show();
}
}
}
2.静态注册实现开机启动
创建一个xx类继承BroadCastReceiver
在AndroidManifest.xml注册静态的广播接收器
在AndroidManifest.xml添加响应广播的action,并且声明该广播的权限
三、发送自定义广播
1.发送标准广播
通过静态注册定义一个广播接收器用于接收自定义的广播
首先构建一个Intent对象,并把要发送的广播的值传入。再调用ContextWrapper的sendBroadcast()方法将广播发送出去
在 Android 8.0 之后,对于广播的发送与接收变严格了,需要加入Component参数
或者按照《第一行代码-第三版》的方法解决:在Android 8.0系统之后,静态注册的BroadcastReceiver是无法接收隐式广播的,而默认情况下我们发出 的自定义广播恰恰都是隐式广播。因此这里一定要调用setPackage()方法,指定这条广播是 发送给哪个应用程序的,从而让它变成一条显式广播,否则静态注册的BroadcastReceiver将 无法接收到这条广播。 注意只有静态注册才写,动态注册不需要写
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.jack.broadcasttest.MY_BROADCAST");
intent.setPackage(getPackageName());
//intent.setComponent(new ComponentName("com.jack.broadcasttest","com.jack.broadcasttest.MyBroadcastReceiver"));
sendBroadcast(intent);
}
});
2.发送有序广播
<receiver
android:name=".AnotherBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.jack.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.jack.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
再注册一个静态接收广播,发现两个receiver都接收到自定义广播,并且和静态注册的顺序相关
Button button = findViewById(R.id.send_broadcast);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.jack.broadcasttest.MY_BROADCAST");
intent.setPackage(getPackageName());
//sendOrderedBroadcast()方法接收两个参数:第一个 参数仍然是Intent;第二个参数是一个与权限相关的字符串,这里传入null就行了。
sendOrderedBroadcast(intent,null);
}
});
<receiver
android:name=".AnotherBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.jack.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
//通过android:priority属性设置优先级
<intent-filter android:priority="100">
<action android:name="com.jack.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();
//abortBroadcast()方法表示将广播截断
abortBroadcast();
}
}
实测 MyBroadcastReceiver可以把广播截断
五、广播的最佳实践---实现强制下线功能
发送自定义广播:
public class MainActivity extends BaseAcitvity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button send = findViewById(R.id.send_forceOffline);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.jack.broadcastreceiverbest.FORCE_OFFLINE");
sendBroadcast(intent);
}
});
}
}
注册一个动态广播接收器:
public class BaseAcitvity extends AppCompatActivity {
private ForceOfflineReceiver forceOfflineReceiver;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}
@Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("com.jack.broadcastreceiverbest.FORCE_OFFLINE");
forceOfflineReceiver = new ForceOfflineReceiver();
registerReceiver(forceOfflineReceiver,filter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(forceOfflineReceiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
class ForceOfflineReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
AlertDialog.Builder builder = new AlertDialog.Builder(BaseAcitvity.this);
builder.setTitle("Warning");
builder.setMessage("You are forced to be offline.Please try to login again");
builder.setCancelable(false);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
ActivityCollector.finishAll();
Intent intent = new Intent(context, LoginActivity.class);
//注意这里的写法,context去掉也行,或者改成BaseActivity.super也行
//为什么context也行呢,查看源码startActivity()是一个抽象方法呀?因为Context类也是一个抽象类,既然有实例context,必然是通过多态间接实现父类的实例化,那么调用的方法肯定是子类已经实现的方法
context.startActivity(intent);
}
});
builder.show();
}
}
}
完!