广播机制

Android中广播主要可以分为两种类型:标准广播和有序广播

  • 标准广播是一种异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播信息,因此他们之间没有先后顺序,也不会被截断;
  • 有序广播是一种同步执行的广播,在广播发出之后,同一时间只有一个广播能接收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,可以被截断;

接收系统广播

Android内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。

动态注册监听网络变化:

注册广播的方式有两种:

  • 在代码中注册:动态注册
  • 在AndroidManifest.xml中注册:静态注册

如何创建一个广播接收器呢?只需要创建一个类,继承自BroadcastReceiver,并重写父类的onReceive()方法就行了。当有广播到来时,onReceive()方法就会执行,具体的逻辑就可以在这个方法中处理。

在MainActivity中定义了一个内部类NetworkChangeReceiver,它继承自BroadcastReceiver,并重写了onReceive()方法。每当网络状态发生变化时,onReceive()方法就会得到执行。

  1. public class MainActivity extends AppCompatActivity {
  2. private IntentFilter intentFilter;
  3. private NetworkChangeReceiver networkChangeReceiver;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. intentFilter = new IntentFilter();
  9. intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
  10. networkChangeReceiver = new NetworkChangeReceiver();
  11. registerReceiver(networkChangeReceiver, intentFilter);
  12. }
  13. class NetworkChangeReceiver extends BroadcastReceiver {
  14. @Override
  15. public void onReceive(Context context, Intent intent) {
  16. Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
  17. }
  18. }
  19. }

首先创建一个IntentFilter实例,并给他添加了一个android.net.conn.CONNECTIVITY_CHANGE的action,监听系统发出的网络状态变化广播。接下来创建一个NetworkChangeReceiver的实例,然后调用registerReceiver方法进行注册,将NetworkChangeReceiver和IntentFilter实例都传进去。

最后,动态注册的广播接收器都需要取消注册才行,这里我们在onDestroy()方法中通过调用unregisterReceiver()方法来实现。

AndroidManifest.xml中添加权限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest">
...
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
...
</manifest>

静态注册实现开机启动:

动态注册的广播接收器可以自由的控制注册和注销,在灵活性方面有很大的优势,但是也存在一个缺点,即必须在程序启动之后才能收到广播,因为注册的逻辑写在onCreate当中,有什么办法可以让程序在未启动的情况下接收到广播?那就是静态注册的方式。

public class BootCompleteReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
    }
}

AndroidManifest.xml中添加receiver以及开机广播的访问权限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest">
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <application ...>
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>

需要注意的是,不要在onReceive()方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中是不允许开启线程的,当onReceive()方法运行了较长时间而没有结束,程序会报错。因此广播接收器一般扮演打开程序其他组件的角色,例如创建一条状态栏通知,启动一个服务等。

发送自定义广播:

sendBroadCast(Intent intent)方法用于发送一个标准的广播:

Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);

sendOrderedBroadcast(intent, null)方法用于发送一个有序的广播,可以在AndroidManifest.xml中设置广播被接受的先后顺序:

<intent-filter android:priority="100">
    <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent-filter>

可以在接收到广播后,停止广播的继续传播:

abortBroadcast()

本地广播机制:

为了防止程序之间的广播互相接收导致的安全问题,Android引入了一套本地广播机制,限制发出的广播只能在应用程序的内部进行传递。

使用LocalBroadcastManager来对广播进行管理。

本地广播机制有以下几个优点:

  • 不必担心机密数据泄露
  • 其他程序无法将广播发送到本程序内部,不许担心安全隐患
  • 发送本地广播比发送系统全局广播更加高效