今天来认识一下Android4大组件中应该是最简单的一个组件:广播BroadcastReceiver
它的作用就跟名字一样,就是一个广播,把要通知的消息告诉所有正在关注、接收这类消息的接收者。
所以这里至少有2方:发送消息的一方和接收消息的一方。发送方不知道要发给谁,只管把这条消息发出去,具体谁接收呢?谁关注谁接收。所以发送的消息需要一个标识,标识这一条是什么消息。
发送方:发送一条带标识的消息
接收方:先注册消息监听,只监听自己感兴趣的消息
上面说到接收方要监听消息,就需要先注册,Android支持2种注册方式:静态注册和动态注册。
静态注册:在Manifest中注册。
优点:可以不用启动apk就能监听到。可以设置优先级
缺点:缺乏灵活性
动态注册:在代码中注册
优点:灵活性高,可以动态的添加。并且在需要的地方注册监听。
缺点:必须启动apk而且启动相关界面。
下面先来看看静态注册:
<receiver
android:name=".MyReceiver1"
android:enabled="true">
<intent-filter>
<action android:name="MyReceiverTest" />
</intent-filter>
</receiver>
receiver表示声明一个广播,android:name=’’是声明广播的类。enable表示是否开启。Intent-filter标签表示我们需要关心的广播消息是什么;下面的action中的内容就是上面提到的消息标识。表示当前这个广播接收器只接收action为MyReceiverTest的消息。这里的action可以有很多条,表示这些消息我们都关注。
下面看看广播接收器的MyReceiver1的内容
class MyReceiver1 : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(context, "onReceive: ${intent!!.action}", Toast.LENGTH_SHORT).show()
}
}
声明一个广播接收器很简单,只需要继承BroadcastReceiver就可以了。然后重写onReceiver方法,当这个方法被调用的时候就表示我们关注的广播有消息来了。
加入我们监听了多条消息,怎么区分呢? 注意第二个参数intent,这里就有带action。我们只要对它做判断就可以了。
下面看看发送消息的地方:
private val BROAD_ACTION = "MyReceiverTest"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
acMainBtSend.setOnClickListener {
val intent = Intent(BROAD_ACTION)
intent.setPackage(packageName)
sendBroadcast(intent)
}
}
布局很简单,就是一个按钮,这里按钮点击发送一条消息。
发送消息也非常简单,只需要调用context的sendBroadcast即可。参数是Intent,Intent有一个构造方法,接收一个String作为action。
注意intent.setPackage(packageName)这一行,在Android8.0以后的手机版本必须添加这一行,不然是收不到消息的。我想Google的这个设置也是为了能监听到广播的来源,不然整个系统里面各种广播满天飞也不好管理。
这样一条消息就发送出去了。大家可以看到这里发送的一方是不需要指定接收者的,那就意味着只要在系统里注册MyReceiverTest这条消息的接收者就都可以收到这条消息。
下面来看看运行的效果
接下来看看动态注册
广播接收器不用改动,主要是在启动apk后要在代码中注册
private val BROAD_ACTION = "MyReceiverTest"
private val myReceiver = MyReceiver1()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//注册广播
val intentFilter = IntentFilter(BROAD_ACTION)
registerReceiver(myReceiver, intentFilter)
acMainBtSend.setOnClickListener {
val intent = Intent(BROAD_ACTION)
intent.setPackage(packageName)
sendBroadcast(intent)
}
}
override fun onDestroy() {
super.onDestroy()
//退出的时候必须注销
unregisterReceiver(myReceiver)
}
注册的时候先创建一个IntentFilter,并且设置action,可以使用intentFilter.addAction来继续添加action。然后调用registerReceiver来注册。注意,注册和注销必须成对出现,我们这里在onDestroy的时候调用了unregisterReceiver来注销。这样就不会再接收到广播了。
效果跟之前的是一样的就不截图了。
之前的广播都是标准的广播用法,Android还提供了一种有序广播,及接收者是有顺序的,并且还可以在中途截断不再继续向后传递。
这类有序广播必须使用静态注册的方式,只需要增加一个参数来表示自己的优先级即可。
为了验证我这里创建了3个广播接收器
<receiver
android:name=".MyReceiver1"
android:enabled="true">
<intent-filter android:priority="100">
<action android:name="MyReceiverTest" />
</intent-filter>
</receiver>
<receiver
android:name=".MyReceiver2"
android:enabled="true">
<intent-filter android:priority="200">
<action android:name="MyReceiverTest" />
</intent-filter>
</receiver>
<receiver
android:name=".MyReceiver3"
android:enabled="true"
android:permission="test">
<intent-filter android:priority="500">
<action android:name="MyReceiverTest" />
</intent-filter>
</receiver>
注意看每个广播的intent-filter里面都增加了一个android:priority属性,其值越大表示优先级越高。
我们在每个广播里面都只是做一个打印,不做任何操作。
修改发送广播,改为发送顺序广播:
val intent = Intent(BROAD_ACTION)
intent.setPackage(packageName)
sendOrderedBroadcast(intent,null)
运行看结果:
可以看到接收的顺序跟我们设置的优先级一样。
那么怎么截断呢?很简单,只需要在接收器里面调用abortBroadcast()就可以了。
我们在MyReceiver2中调用这个方法
class MyReceiver2 : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d("ZLog MyReceiver2", "onReceive: ${intent!!.action}")
abortBroadcast()
}
}
发送的方法不用改变
看看运行效果:
可以看到MyReceiver1并没有接收到消息。
到这里怎么发送广播就差不多这些了。其实广播不只是简单的发送一条消息,还可以携带数据的。大家注意我们发送广播的参数和接收到广播的回调参数都是intent,看过我的Activity详解2应该知道,intent是可以带数据的。通过它我们可以实现线程、进程之间的通讯和传递数据。后面我们会讲到Android的进程间通讯,广播就是其中一种方式。