Android中的广播机制主要可以分为两种类型:标准广播和有序广播
标准广播是一种完全异步执行的广播,在广播放出 之后 ,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序。这种广播效率会很高,但是不能被截断;
有序广播是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够接收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。
注册广播接收器的方式一般有两种,在代码中注册和在AndroidManifest.xml中注册,前者为动态注册,后者为静态注册
一、动态注册监听网络变化
创建一个广播接收器:需要注册一个类,让他继承BroadcastReceiver,并重写父类的onReceiver()方法即可。当有广播来临时,onReceiver()方法就会得到执行,具体逻辑就可以在这个方法中处理。
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);
}
/*新建NetWorkChangeReceiver类,并重写onReceive方法*/
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(MainActivity.this,"network is available",Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(MainActivity.this,"network is unavailable",Toast.LENGTH_SHORT).show();
}
}
}
}
创建了一个IntentFilter的实例,并给它添加了一个值为android.net.conn.CONNECTIVITY_CHANGE的action,当网络状态发生变化时,系统发出的正是一条值为android.net.conn.CONNECTIVITY_CHANGE的广播,也就是说我们的广播接收器想要监听什么广播,就在这里添加相应的action,然后创建了一个NetWorkChangeReceiver 实例,然后调用registerReceiver()方法进行注册,将NetWorkChangeReceiver 和IntentFilter实例都传进去,这样NetWorkChangeReceiver 就会收到所有值为android.net.conn.CONNECTIVITY_CHANGE的广播,也就实现了网络监听功能。
最后,动态注册的广播接收器一定要取消注册这里使用onDestroy()中的unregisterReceiver()方法来实现的。
在onReceiver()方法中,首先通过getSystemService()方法得到了ConnectivityManager的实例,这是一个系统服务类,专门用于管理网络连接的。然后调用它的getActiveNetworkInfo()方法可以得到NetworkInfo实例,接着调用NetworkInfo的isAvailable()方法判断当前是否有网络。
访问系统的网络状态需要在AndroidManifest.xml中声明权限
< uses-permission android:name=“android.permission.ACCESS_NETWO RK_STATE” />
二、静态注册实现开机启动
动态注册广播接收器可以自由地控制注册于注销,在灵活性方面有很大优势,但是存在一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在onCreate()方法中的。
难得抄笔记了,就将就用别人的吧:
参考博客
三、发送标准广播
关于标准广播的概念上面描述了的。
1、创建一个广播接收器(用于接收我们发出的广播)
这里采用的是静态注册广播接收器
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show();
}
}
当接收到自定义的广播时,就会弹出received in MyBroadcastReceiver
修改AndroidManifest.xml:
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcastReceiver"/>
</intent-filter>
</receiver>
让MyBroadcastReceiver 广播接收器接收值为com.example.broadcastReceiver的广播,待会发送广播的时候,我们就需要发送这样一条广播。
2、发送广播
设置一个Button用于点击发送广播
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<Button
android:id="@+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Send Broadcast"
android:textAllCaps="false"/>
</LinearLayout>
设置Button点击事件:
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetWorkChangeReceiver netWorkChangeReceiver;
private Button button1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1=(Button)findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent("com.example.broadcastReceiver");
sendBroadcast(intent);
}
});
}
}
构建一个Intent对象,并把要发送的广播的值传入,然后调用Context的sendBroadcast()方法将广播发送出去,这样监听com.example.broadcastReceiver广播的接收器都会收到消息。这就是一条标准广播。
四、发送有序广播
在AndroidManifest.xml文件中设置接收器的优先级(android:priority属性),可以达到接收器先后收到广播的效果,然后在活动中将发送标准广播的sendBroadcast()方法改成sendOrderedBroadcast()方法,最后有序广播的一个特点就是可以截停在广播接收器文件中添加 abortBroadcast();可以将广播截停。
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show();
}
}
public class AnotherBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"received in AnotherBroadcastReceiver",Toast.LENGTH_SHORT).show();
abortBroadcast();
}
}
AnotherBroadcastReceiver 广播接收器接收到广播后会进行截断,如果这里不截断,优先级低于它的接收器会收到广播。
<receiver
android:name=".AnotherBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.broadcastReceiver" />
</intent-filter>
</receiver>
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcastReceiver" />
</intent-filter>
</receiver>
两个广播接收器的注册代码,可以看到AnotherBroadcastReceiver 的优先级大于MyBroadcastReceiver,所以AnotherBroadcastReceiver 先接收到值为com.example.broadcastReceiver的广播。
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetWorkChangeReceiver netWorkChangeReceiver;
private Button button1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1=(Button)findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent("com.example.broadcastReceiver");
sendOrderedBroadcast(intent,null);
}
});
}
}
使用sendOrderedBroadcast()方法发送广播。
五、使用本地广播
前面发送和接收的广播全部属于系统全局广播,系统全局广播有安全性问题 ,android引入一套本地广播机制,使用这个机制发出的广播只能够在应用程序的内部传递。本地广播主要使用LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法。
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private Button button1;
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
localBroadcastManager=LocalBroadcastManager.getInstance(this);//获取实例
button1=(Button)findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
//sendBroadcast(intent);
localBroadcastManager.sendBroadcast(intent); //发送本地广播
}
});
intentFilter=new IntentFilter();
intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
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, "received local broadcast", Toast.LENGTH_SHORT).show();
}
}
}
本地广播是无法通过静态注册方式来接收的,因为发送本地广播时,我们的程序肯定是启动了的。