BrocastReceiver广播的使用

1,102 阅读6分钟

ACTION_BOOT_COMPLETED:系统启动完成。

ACTION_PACKAGE_ADDED:系统添加包。

ACTION_PACKAGE_REMOVED:系统的包被删除。

ACTION_PACKAGE_DATA_CLEARED:系统的包数据被清空。

ACTION_BATTERY_CHANGED:电池电量改变。

ACTION_BATTERY_LOW:电池电量低。

ACTION_TIME_CHANGED:系统时间被改变。

ACTION_DATE_CHANGED:系统日期被改变。

ACTION_TIMEZONE_CHANGED:系统时区被改变。

上面这些Action是什么?这些就是 系统广播

前言:广播是什么?

广播有系统广播和应用广播

系统广播

系统自己在很多时候都会发送广播,比如上面列出上面列出的系统启动完成、系统添加包、电池电量低等,系统都会发送广播,这台手机上的每个APP都会收到,当然由于现在Android隐私安全越来越严格,所以有些广播接收还受到严格的权限控制。

应用广播

应用自定义一些广播,可以用于进程间通信。 例如:应用程序可以发送广播来传递数据给其他应用,或者通知其他应用你完成了什么事。

广播接收者(BroadcastReceiver) Android四大组件之一,通信的一种手段,广播接收者用于接收来自其他应用程序或者系统的广播消息。

这篇文章主要是讲解自定义广播的使用。

广播.gif

一.两种注册方式:动态&静态

1.动态注册

注册:

IntentFilter filter = new IntentFilter();
filter.addAction("com.example.dynamic");
//注册广播接收
registerReceiver(new DynamicReceiver(), filter);

解绑:

unregisterReceiver(new DynamicReceiver());

发送广播:

//动态广播
Intent intent = new Intent();
intent.setAction("com.example.dynamic");
intent.putExtra("value", "你好!");
sendBroadcast(intent);

继承BroadcastReceiver 的 DynamicReceiver 类:

public class DynamicReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "动态广播:" + intent.getStringExtra("value"), Toast.LENGTH_LONG).show();
        Log.d(getClass().getSimpleName() + "-TEST", "动态广播");
    }
}

2.静态注册

清单文件配置:

<receiver android:name=".broadcast.StaticReceiver">
    <intent-filter>
        <action android:name="com.example.static" />
    </intent-filter>
</receiver>

发送广播:

//静态广播
Intent intent = new Intent("com.example.static");
intent.putExtra("value", "你好!");
//应用内广播,解决android 8.0 无法接受静态注册广播问题。
intent.setClassName(MainActivity.this, "com.example.myfirstproject.broadcast.StaticReceiver");
sendBroadcast(intent);

继承BroadcastReceiver 的 StaticReceiver 类:

public class StaticReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "静态广播:" + intent.getStringExtra("value"), Toast.LENGTH_LONG).show();
        Log.d(getClass().getSimpleName(), "静态广播");
    }
}

注意:如果你的安卓版本是8.0+,静态注册需要加下面这段代码才能在你应用内的Receiver接收到静态注册广播。

intent.setClassName(MainActivity.this, "com.example.myfirstproject.broadcast.StaticReceiver");

如果你需要向其他应用中静态注册的广播接收者发送广播,加上下面代码试试:

//该方式适用:给其他应用的广播接收者发送消息(指定应用的包名、指定类的全类名)

intent.setComponent(new ComponentName("包名", "包名.XXXReceiver"));

官方说明:Beginning with Android 8.0 (API level 26), the system imposes additional restrictions on manifest-declared receivers. If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for most implicit broadcasts (broadcasts that do not target your app specifically).

意思就是说:从android 8.0(API 26)开始,对清单文件中静态注册广播接收者增加了限制,建议大家不要在清单文件中静态注册广播接收者

二.普通广播&有序广播

为了验证下普通广播和有序广播的区别,需要在增加一个动态广播接收者Dynamic2Receiver。代码同上面动态注册的DynamicReceiver一样。

public class Dynamic2Receiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "动态广播2:" + intent.getStringExtra("value"), Toast.LENGTH_LONG).show();
        Log.d(getClass().getSimpleName() + "-TEST", "动态广播2");

        //拦截广播
        //abortBroadcast();
    }
}

接下来动态注册两个接收者Receiver,增加优先级setPriority,注意区别两个接收者的优先级:Dynamic2Receiver是1000优先级高于DynamicReceiver-1000,也就是Dynamic2Receiver要优先于DynamicReceiver接收到广播。

IntentFilter filter = new IntentFilter();
filter.addAction("com.example.dynamic");
//注册广播接收
filter.setPriority(-1000);
registerReceiver(new DynamicReceiver(), filter);

//注册广播接收
filter.setPriority(1000);
registerReceiver(new Dynamic2Receiver(), filter);

//本地广播
localBroadcastManager = LocalBroadcastManager.getInstance(this);
filter.addAction("com.example.local");
localBroadcastManager.registerReceiver(new LocalReceiver(), filter);

同样有注册就要有解绑:

@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(new DynamicReceiver());
    unregisterReceiver(new Dynamic2Receiver());
}

接下来看下不同的广播发送方式的区别。

1.普通广播

Intent intent = new Intent();
intent.setAction("com.example.dynamic");
intent.putExtra("value", "你好!");
sendBroadcast(intent);

标准广播的发送方式,接受者是异步执行。

输出Log:

2021-08-06 13:24:09.396 11531-11531/com.example.myfirstproject D/Dynamic2Receiver-TEST: 动态广播2
2021-08-06 13:24:09.424 11531-11531/com.example.myfirstproject D/DynamicReceiver-TEST: 动态广播

1.有序广播

Intent intent = new Intent();
intent.setAction("com.example.dynamic");
intent.putExtra("value", "你好!");
sendOrderedBroadcast(intent, null);

输出Log:

2021-08-06 13:26:21.591 12332-12332/com.example.myfirstproject D/Dynamic2Receiver-TEST: 动态广播2
2021-08-06 13:26:21.756 12332-12332/com.example.myfirstproject D/DynamicReceiver-TEST: 动态广播

使用sendOrderedBroadcast发送有序广播。接收者是按优先级高到低进行执行。 并且我们可以在优先级高的接收者Dynamic2Receiver对广播进行拦截,这样DynamicReceiver就不会执行了。

对广播进行拦截使用如下代码:

    //拦截广播
     abortBroadcast();

加上拦截代码输出:

2021-08-06 13:25:35.709 12085-12085/com.example.myfirstproject D/Dynamic2Receiver-TEST: 动态广播2

突发奇想,在普通广播加上abortBroadcast();会有什么反应呢?

结果是程序不会崩溃但是LogCat里有错误log:

BroadcastReceiver trying to return result during a non-ordered broadcast

三.本地广播

已经有了全局广播为什么还要增加一个本地广播呢?

这是因为BroadcastReceiver的设计初衷是全局性,可接收来自本应用和其他应用发过来的intent广播。这也同时给app带来了一定的安全风险。为了解决这个问题,Android增加了本地广播LocalBroadcastManager。

LocalBroadcastManager 只会将广播限定在当前应用程序中。LocalBroadcastManager 发送的广播不会离开你的应用程序,同样也不会接收来自其它应用程序的广播,因此你可以放心的在 LocalBroadcastManager 中传播敏感信息,而不会被其他应用截取。同时由于LocalBroadcastManager不需要用到跨进程机制,因此相对 BroadcastReceiver 而言要更为高效。LocalBroadcastManager只在动态广播时使用,静态广播不能使用LocalBroadcastManager。

所以如果你没有跟其他应用通信的需求的广播优先使用LocalBroadcastManager。

熟悉了上面动态注册发送接受广播,本地广播就很简单了。

本地广播都是通过LocalBroadcastManager来进行调用管理的。

private LocalBroadcastManager localBroadcastManager;

注册本地广播:

IntentFilter filter = new IntentFilter();
//本地广播
localBroadcastManager = LocalBroadcastManager.getInstance(this);
filter.addAction("com.example.local");
localBroadcastManager.registerReceiver(new LocalReceiver(), filter);

解绑本地广播:

localBroadcastManager.unregisterReceiver(new LocalReceiver());

调用本地广播:

Intent intent = new Intent();
intent.setAction("com.example.local");
intent.putExtra("value", "你好!");
localBroadcastManager.sendBroadcast(intent);

定义一个接收者Receiver:

public class LocalReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "本地广播:" + intent.getStringExtra("value"), Toast.LENGTH_LONG).show();
        Log.d(getClass().getSimpleName() + "-TEST", "本地广播");
    }
}

以上,其实跟动态注册大部分代码重合。只需要在注册,解绑,发送广播中通过LocalBroadcastManager来管理就可以了。

输出Log:

2021-08-06 13:28:37.218 12332-12332/com.example.myfirstproject D/LocalReceiver-TEST: 本地广播

结语

以上就是关于广播的一些介绍了。如果你还感兴趣系统广播的使用方式,可以再看看我的这篇文章,# Android开机自启动的两种方式,里面对系统开机广播作了介绍:

传送门: # Android开机自启动的两种方式