Android应用软件开发

194课时
1.7K学过
8分

课程评价 (0)

请对课程作出评价:
0/300

学员评价

暂无精选评价
3分钟

4.3 相关知识

相关知识

在Android中,Broadcast是四大组件之一,也是一种广泛运用在应用程序之间传输信息的机制,Android中发送的广播内容是一个Intent,这个Intent中可以携带我们要发送的数据。

Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器)。

广播作为Android组件间的通信方式,可以使用的场景如下:

  • l 同一app内有多个进程的不同组件之间的消息通信。
  • l 不同app之间的组件之间消息的通信。

从实现原理看上,Android中的广播使用了观察者模式,基于消息的发布/订阅事件模型。因此,从实现的角度来看,Android中的广播将广播的发送者和接受者极大程度上解耦,使得系统能够方便集成,更易扩展。

广播被分为两种不同的类型:“无序广播(Normal broadcasts)”和“有序广播(Ordered broadcasts)”。无序广播是完全异步的,可以在同一时刻(逻辑上)被所有广播接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播;然而有序广播是按照接收者声明的优先级别(声明在intent-filter元素的android:priority属性中,数越大优先级别越高,取值范围:-1000到1000。也可以调用IntentFilter对象的setPriority()进行设置),被接收者依次接收广播。如:A的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C。A得到广播后,可以往广播里存入数据,当广播传给B时,B可以从广播中得到A存入的数据。

无序广播使用Context.sendBroadcast()方法发送,所有订阅者都有机会获得并进行处理。

有序广播使用Context.sendOrderedBroadcast()发送,系统会根据接收者声明的优先级别按顺序逐个执行接收者,前面的接收者有权终止广播,如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。对于有序广播,前面的接收者可以将处理结果存放进广播Intent,然后传给下一个接收者。

广播接收者(BroadcastReceiver)用于接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收。要实现一个广播接收者方法如下:

第一步:定义广播接收者,继承BroadcastReceiver,并重写onReceive()方法。

 public class IncomingSMSReceiver extendsBroadcastReceiver {      @Override public void onReceive(Contextcontext, Intentintent) {      }   }   

第二步:订阅感兴趣的广播Intent,订阅方法有两种:

第一种:使用代码进行订阅(动态订阅)

IntentFilter filter =  newIntentFilter("android.provider.Telephony.SMS_RECEIVED");   IncomingSMSReceiver receiver = newIncomingSMSReceiver();   registerReceiver(receiver, filter);  

第二种:在AndroidManifest.xml文件中的<application>节点里进行订阅(静态订阅)

<receiver  android:name=".IncomingSMSReceiver">      <intent-filter>       <action android:name="android.provider.Telephony.SMS_RECEIVED"/>      </intent-filter>   </receiver>   

动态广播订阅和静态广播订阅的区别如下:

静态订阅广播又叫常驻型广播,当你的应用程序关闭了,如果有广播信息来,你写的广播接收器同样的能接受到,他的注册方式是在应用程序中的AndroidManifast.xml进行订阅的。

动态订阅广播又叫非常驻型广播,当应用程序结束了,广播自然就没有了,在activity中的onCreate或者onResume中订阅广播,同时你必须在onDestory或者onPause中取消广播订阅,不然会报异常。

在发送广播的时候需要注意的是动态注册的时候使用的是隐式intent方式的,所以在发送广播的时候需要使用隐式Intent去发送,不然是广播接收者是接收不到广播的。但是静态订阅的时候,因为在AndroidMainfest.xml中订阅的,所以在发送广播的时候使用显示Intent和隐式Intent都可以(当然这个只针对于自定义的广播接收者),所以以防万一,一般都采用隐式Intent去发送广播。

Android 3.1开始系统在Intent与广播相关的flag增加了参数,分别是FLAG_INCLUDE_STOPPED_PACKAGES(包含已经停止的包)和FLAG_EXCLUDE_STOPPED_PACKAGES(不包含已经停止的包)。自Android3.1开始,系统本身则增加了对所有app当前是否处于运行状态的跟踪。在发送广播时,不管是什么广播类型,系统默认直接增加了值为FLAG_EXCLUDE_STOPPED_PACKAGES的flag,导致即使是静态注册的广播接收器,对于其所在进程已经退出的app,同样无法接收到广播。

由此,对于系统广播,由于是系统内部直接发出,无法更改此intent flag值,因此,3.1开始对于静态注册的接收系统广播的BroadcastReceiver,如果App进程已经退出,将不能接收到广播。

但是对于自定义的广播,可以通过复写此flag为FLAG_INCLUDE_STOPPED_PACKAGES,使得静态注册的BroadcastReceiver,即使所在App进程已经退出,也能能接收到广播,并会启动应用进程,但此时的BroadcastReceiver是重新新建的。

Intent intent = new  Intent();  intent.setAction(BROADCAST_ACTION);  intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);  intent.putExtra("name",  "qqyumidi");  sendBroadcast(intent);  

使用广播有两个步骤:

\1. 广播的接收者需要通过调用registerReceiver函数告诉系统,它对什么样的广播有兴趣,即指定IntentFilter,并且向系统注册广播接收器,即指定BroadcastReceiver:

  IntentFilter counterActionFilter = new IntentFilter(  CounterService.BROADCAST_COUNTER_ACTION);   registerReceiver(counterActionReceiver, counterActionFilter);   

这里,指定感兴趣的广播就是CounterService.BROADCAST_COUNTER_ACTION了,而指定的广播接收器就是counterActonReceiver,它是一个BroadcastReceiver类型的实例。

\2. 广播的发送者通过调用sendBroadcast函数来发送一个指定的广播,并且可以指定广播的相关参数。

Intent intent = new Intent(BROADCAST_COUNTER_ACTION);   intent.putExtra(COUNTER_VALUE, counter);   sendBroadcast(intent) ;  

指定的广播为CounterService.BROADCAST_COUNTER_ACTION,并且附带的带参数当前的计数器值counter。调用了sendBroadcast函数之后,所有注册了CounterService.BROADCAST_COUNTER_ACTION广播的接收者便可以收到这个广播了。

在第1步中,广播的接收者把广播接收器注册到ActivityManagerService中;在第2步中,广播的发送者同样是把广播发送到ActivityManagerService中,由ActivityManagerService去查找注册了这个广播的接收者,然后把广播分发给它们。

在第2步的分发的过程,其实就是把这个广播转换成一个消息,然后放入到接收器所在的线程消息队列中去,最后就可以在消息循环中调用接收器的onReceive函数了。这里有一个要非常注意的地方是,由于ActivityManagerService把这个广播放进接收器所在的线程消息队列后,就返回了,它不关心这个消息什么时候会被处理,因此,对广播的处理是异步的,即调用sendBroadcast时,这个函数不会等待这个广播被处理完后才返回。