Android必读之BroadcastReceive基础

Android应用程序可以发送或接收来自Android系统和其他Android应用程序的广播消息,类似于发布订阅设计模式。例如,当各种系统事件发生时,如系统启动或设备开始充电时,Android系统会发送广播。例如,应用程序还可以发送自定义广播,通知其他应用程序他们可能感兴趣的内容(例如,已下载了一些新数据)。
应用程序可以注册以接收特定的广播。当发送广播时,系统自动将广播发送到订阅接收该特定类型广播的应用程序。
不要滥用响应广播,这可能导致系统性能变慢。
广播也是一种进程间通信的一种方式。

广播注册

BroadcastReceive有两种注册方式,全局静态注册和动态注册。
静态注册大致分为两步:

  1. 继承BroadcastReceive类来实现自己的广播,比如:
    public class MyBroadcastReceiver extends BroadcastReceiver {
            private static final String TAG = "MyBroadcastReceiver";
            @Override
            public void onReceive(Context context, Intent intent) {
                StringBuilder sb = new StringBuilder();
                sb.append("Action: " + intent.getAction() + "n");
                sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "n");
                String log = sb.toString();
                Log.d(TAG, log);
                Toast.makeText(context, log, Toast.LENGTH_LONG).show();
            }
        }
  2. 在AndroidMnifest.xml使用receive元素进行清单声明的方式
    <receiver android:name=".MyBroadcastReceiver"  android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
        </intent-filter>
    </receiver>

    使用intent-filter制定过滤条件。

当用户安装Apk启动App后广播就会启动处于监听状态。

注意:如果App设置targetSdkVersion>=26,App在被杀死以后就不会接收到广播消息。

动态注册:如果大量的使用全局静态注册会影响到App性能,会导致卡顿问题的出现,所以,一般情况下我们都是使用静态注册的方式使用广播,比如在Activity中注册一个广播:

    private final static String ACTION_1 = "ACTION_1";
    private final static String ACTION_2 = "ACTION_2";
    private MyBroadcastReceive myBroadcastReceive = new MyBroadcastReceive();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ACTION_1);
        intentFilter.addAction(ACTION_2);//可以添加多个Action
        registerReceiver(myBroadcastReceive, intentFilter);
    }
    class MyBroadcastReceive extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(ACTION_1)) {
                //处理Action1的逻辑
            } else if (intent.getAction().equals(ACTION_2)) {
                //处理Action2的逻辑
            }
        }
    }

动态注册广播的声明周期与Context(比如Activity)的声明周期是一致的。
解除注册:

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(myBroadcastReceive);
    }

注意注册和注销广播的位置,例如,如果在OnCreate(bundle)中注册,则应在OnDestroy()中注销它,以防止发生内存泄漏。如果在onresume()中注册,则应在onpause()中注销它,以防止多次注册它(如果您不希望在暂停时接收广播,这可以减少不必要的系统开销)。

发送广播

按照Android官方文档的说法,Android有三种发送广播的方式,它们分别是:

  • sendOrderedBroadcast(Intent, String) 有序广播,我们可以通过adroid:prority设置广播的优先级,级别高的优先接受到广播。当优先级高的广播接收器的 onReceiver() 方法运行结束后,广播才会继续传递,且前面的广播接收器可以选择截断广播,这样后面的广播接收器就无法接收到这条广播了。优先级相同的广播以任意顺序接受到广播。
  • sendBroadcast(Intent) 标准广播或者叫无序广播。因为没有先后顺序,所以效率更高,也是我们普遍选择使用的方式。
    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //省略部分代码
            findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    sendBroadcast(ACTION_1, "hello");
                }
            });
            findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    sendBroadcast(ACTION_1, " world!");
                }
            });
        }
        private void sendBroadcast(String action, String msg) {
            Intent intent = new Intent();
            intent.setAction(action);
            intent.putExtra("MSG", msg);
            sendBroadcast(intent);
        }
  • LocalBroadcastManager.sendBroadcast 顾名思义,如果注册的广播不进行跨进程通信使用,那么就使用这种方式进行发送广播。它的实现更加高效(因为不需要跨进程通信)。所以如果你需要进行监听系统相关信息的变化就不要使用这个。比如网路监听。因为只是在本进程内使用,所以也十分安全,不用担心数据泄露等问题。

Broadcast功能变更

随着Android系统的不断版本更新,Android 广播功能也不断变化,如果你的App是针对Android7(API24)或者更高的设备,请谨记一下几点变化:r.

Android 9

从 Android 9 (API level 28)开始, NETWORK_STATE_CHANGED_ACTION 广播不接收有关用户位置或个人可识别数据的信息。
此外,如果您的应用程序安装在运行Android 9或更高版本的设备上,则来自Wi-Fi的系统广播不包含SSID、BSSID、连接信息或扫描结果。要获取此信息,请改为调用getConnectionInfo()。

Android 8.0

从Android 8.0 (API level 26)开始, 关于静态注册系统强制执行了一些额外的限制,不能再注册隐式广播,更多请阅读Android O 对隐式广播的限制以及对策

Android 7.0

Android 7.0 (API level 24)以及更高版本不再发送一下广播:

此外,针对Android 7.0及更高版本的应用程序必须使用registerReceiver(BroadcastReceiver, IntentFilter).注册连接操作广播。在清单中声明接收者不起作用。

点赞

发表评论