广播简介:

为什么说 Android 中的广播机制更加灵活呢?这是因为 Android 中的每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接受自己所关心的广播内容,这些广播内容可能是来自于系统,也可能是来自于其他应用程序的。Android 提供了一整套的 API,允许应用程序自由地发送和接受广播。

广播分为两大类:

  • 标准广播(Normal broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接受到这条广播消息,因此它们之间没有任何先后顺序可言,这种广播的效率会比较高,但同时也意味着它是无法被拦截的。
  • 有序广播(Ordered broadcasts) 则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接受器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。

1.接受系统广播

Android 内置了很多系统级别的广播,我们可以在应用中通过监听这些广播来得到各种系统的状态信息。比如手机开机后会发送一条广播,电池的电量发生变化会发出一条广播,时间或时区发生改变也会发出一条广播等等。如果想要接受这些广播,就需要使用广播接收器。

1.1注册广播方式一般有两种:

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

1.1.1 动态注册监听网络变化

代码如下:
权限

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
private  NetWorkChangeReceiver netWorkChangeReceiver;
    private IntentFilter intentFilter;

  private void init() {

         intentFilter = new IntentFilter();
         intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
         netWorkChangeReceiver = new NetWorkChangeReceiver();
         //注册广播
        registerReceiver(netWorkChangeReceiver,intentFilter);
    }




    private class NetWorkChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //系统服务类
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

            NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
            //判断网络是否可用
            if (activeNetworkInfo!=null && activeNetworkInfo.isAvailable()){
                Toast.makeText(BroadCastsActivity.this,"网络可用",Toast.LENGTH_SHORT).show();

            }else {
                Toast.makeText(BroadCastsActivity.this,"网络不可用",Toast.LENGTH_SHORT).show();

            }

        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        //销毁广播
        unregisterReceiver(netWorkChangeReceiver);
    }

1.1.2 静态注册广播实现开机启动:

动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势,但是它也存在着一个缺点,即必须要在程序启动之后才能接受到广播,因为注册的逻辑是写在 onCreate()方法中的。那么有没有什么方法可以让程序在未启动的情况下就能接受到广播呢?这就需要使用静态注册方式了。

我们将广播接受器命名为 MyReceiver;

  • Export 属性表示是否允许这个广播接收器接受本程序以外的广播;
  • Enable 属性表示是否启用这个广播接受器;

我们使用 Android的快捷方式创建广播接收器,因此注册被自动完成了,打开 AndroidManifest.xml文件看一下:

<receiver
            android:name=".service.MyReceiver"
            android:enabled="true"
            android:exported="true">
            <!--监听开机广播 -->
          <intent-filter>
              <action android:name="android.intent.action.BOOT_COMPLETED"/>
          </intent-filter>
    </receiver>

权限必须手动配置:开机广播

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

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

作者:因为我的心
链接:https://www.jianshu.com/p/53e6abd8bfc7
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

/**
 * 广播接受器
 */
public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {


        Toast.makeText(context,"开机广播",Toast.LENGTH_LONG).show();


    }
}

2.1发送自定义广播

2.1.1 发送标准广播

代码如下:
注册广播

<receiver
            android:name=".service.MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">

            <intent-filter>
                <action android:name="com.function.luo.MyBroadcastReceiver" />
            </intent-filter>
  </receiver>

重写广播方法:

public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"发送标准广播",Toast.LENGTH_LONG).show();
    }
}

调用广播方法:

Intent intent = new Intent("com.function.luo.MyBroadcastReceiver");
                 sendBroadcast(intent);

2.1.2 发送有序广播

广播是一种跨进程的通信方式,这一点从前面接受系统广播的时候就可以看出来了。因此在我们应用程序内发出的广播,其它应用程序也是可以接受的。

//发送有序广播
 Intent intent = new Intent("com.function.luo.MyBroadcastReceiver");
                 sendOrderedBroadcast(intent,null);

第一个参数是 Intent;
第二个参数是一个与权限相关的字符串,这里传 null 就行了

<receiver
            android:name=".service.MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">

            <intent-filter
                android:priority="100"
                >
                <action android:name="com.function.luo.MyBroadcastReceiver" />
            </intent-filter>
        </receiver>

android:priority="100" 设置优先级,优先级较高的广播接收器就可以先收到广播。

public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"发送标准广播",Toast.LENGTH_LONG).show();
        //拦截广播
        abortBroadcast();
    }
}

在onReceive()方法中调用了 abortBroadcast()方法,就表示这条广播截断,后面的广播接收器无法再接受到这条广播。

3.1 使用本地广播

简介:

前面我们发送和接受的广播全部属于系统全局广播,即发出的广播可以被其它任何应用程序接收到,并且我们也可以接受来自于其它任何应用程序的广播。

为了解决广播安全性问题,Android 引入了一套本地广播机制,使用这个机制发出的广播只能在应用程序内部进行传递,并且广播接受器也只能接受来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。

初始化广播:

private LocalBroadcastManager localBroadcastManager;

    private void init() {
        //获取实例
        localBroadcastManager = LocalBroadcastManager.getInstance(this);

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("om.function.luo.LOCAL_BROADCAST");
        LocalReceiver localReceiver = new LocalReceiver();
        localBroadcastManager.registerReceiver(localReceiver, intentFilter);
        
    }

发送本地广播

Intent intent = new Intent("om.function.luo.LOCAL_BROADCAST");
        localBroadcastManager.sendBroadcast(intent);

重写广播接受方法

private class LocalReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "本地广播.....", Toast.LENGTH_LONG).show();
        }
    }

注意:

本地广播是无法通过静态注册的方式来接收的,其实这也完全可以理解,因为静态注册主要是为了让程序在未启动的情况下也能接受到广播,而发送本地广播时,我们的程序已经启动了,因此也完全不需要使用静态注册的功能。

本地广播的优势

  • 可以明确知道正在发送的广播不会离开我们的程序,因此不必担心机密数据泄露。
  • 其它的程序无法将广播发送到我们程序内部,因此不需要担心会有安全漏洞问题。
  • 发送本地广播比发送系统全局广播更加高效。

广播常用的地方:

类似 QQ强制下线功能,出现一个弹窗,杀死所有 Activity,强制进入登录页面(可以选用,静态广播,动态广播或者本地广播)。