第11回 我猜小曹不会用Broadcast
2015-11-11 18:38
232 查看
刘关张听完孔明的讲解之后,恍然大悟,深感Service的博大精深。
孔明喝了口茶,道:“唉,这说的我口干舌燥,还好我智商够高,嘴皮够快,心肠够好,不然怎么教会你们呀。”
张飞接道:“军师的脸皮也够厚……”
还没等张飞说完,刘备随手拿起一个花盆就糊到张飞脸上!“三弟,不许侮辱军师!”
张飞扒掉脸上的土,抱怨道:“大哥,你咋对我脸意见这么大……”
刘备语重心长道:“唉,我这也是为你好呀,只有成为大牛才能赢得大家的尊重哇。”
孔明赶紧道:“翼德也是心直口快,没关系,对了,面试官都问了你啥?”
张飞歪了歪嘴,说:“别提了!一进去就看一壮汉翘个二郎腿在那嗑瓜子,爷爷我哪里还能看得下去,进去就是一招猴子偷桃攻他下盘,他一招仙人指路点我胸口。就这么我一招偷桃,他一招指路,我一招偷桃,他一招指路,打得好不欢乐。直到后来大哥叫我我这才走的,他还约我有时间再来打过,好像叫‘许猪’什么的。”
刘备、关羽、孔明三人听张飞说完,琢磨了好一会儿,也没能理解张飞是怎么个思想感情,为啥看人嗑瓜子就不爽了。
关羽摇了摇头道:“言归正传,我们还是太年轻了,还是应该多学学再去嚣张啊!这下倒好,尊严全无啊,以后还怎么在道上混啊。”
孔明说:“怕什么,这世上又不止曹操那一家的,而且你们的志向不是做出自己的产品吗?原来的骨气都哪去了?”
刘备说:“是呀!我们一定要做出比小曹还牛的产品,到时候威震四方,让小曹羡慕嫉妒恨去吧!”
孔明说:“我决定先对你们进行一个系统的集训,好好补一下Android的基本知识。嗯……首先就从Broadcast开始!”
在Andoird中Broadcast是应用程序间传输消息的一种机制,通过Broadcast可以通知其他组件某个事件已经发生了,比如电量不足、wifi连接等,许多应用程序都可以接收Broadcast消息。Android的Broadcast机制主要由以下三部分组成:
l Broadcast:用于发送广播,即说明某件事情发生了,提醒相关的组件。
l BraodcastReceiver:用于接收广播,并进行相应处理。
l Intent:用于保存广播的相关信息(包括事件内容与用于过滤的信息)。
Broadcast的具体工作方式是这样的:在需要发送信息的地方,将需要发送的信息和用于过滤的信息(action、category等)装入一个Intent对象,然后调用Context.sendBroadcast()方法,将Intent对象发送出去。当Intent发送出去之后所有已经注册的BroadcastReceiver组件都会检测注册的intent-filter是否与该Intent相匹配,如果匹配则调用BroadcastReceiver的onReceive()方法,对Intent进行处理。
发送Broadcast代码清单11-2-1:
/**
* @author 刘备至张飞短信:“呵呵,干嘛呢?”
*/
publicclass SendBroadCastListener implements OnClickListener{
@Override
public void onClick(View arg0){
// intent就是我们要发送的内容
Intent intent = new Intent();
intent.putExtra("data", "broadcast”));
//设置你这个广播的action,
//BroadcastReciever的intent-filter会与action进行匹配,确定是否接收
intent.setAction(action);
//发送广播
sendBroadcast(intent);
}
}
表11-1 Broadcast action
//军师,我懂了,你再看看我小飞飞写的BroadcastReceiver实现,如何?
public class MyReceiverextends BroadcastReceiver {
@Override
//收到broadcast时会执行onReceive函数
public void onReceive(Context context, Intent intent) {
//显示出Toast
Toast.makeText(context,“The receiver of broadcast1 is started.. “).show();
}
}
静态注册
在manifest中用<receiver>标签进行声明,并使用<intent-filter>标签注册过滤器,代码如下所示:
<receiverandroid:name=".SMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
动态注册
动态注册在代码中先定义并设置好一个IntentFilter对象,然后使用Context.registerReceiver()方法进行注册,如果BroadcastReceiver需要注销则调用Context.unregisterReceiver()方法,代码如下所示:
BroadcastReceiver的实现方法代码清单11-3-2:
/**
* @author 刘备至张飞短信:“呵呵,刚才在干嘛呢?”
*/
public class MyBroadcastReceiverextends Activity {
private BroadcastReceiver receiver;
//在Activity启动时注册一个BroadcastReceiver
@Override
protected void onStart() {
super.onStart();
//MyReceiver是一个自定义Receiver
receiver = new MyReceiver ();
//注册Receiver,并创建相应的IntentFilter对象
registerReceiver(receiver,
new IntentFilter("android.intent.action.PHONE_STATE"));
}
//在Activity停止时进行注销
@Override
protected void onStop() {
//注销
unregisterReceiver(receiver);
super.onStop();
}
}
SmsShield代码清单11-4-0:
/**
* 动态注册BroadcastReceiver
* ——大哥,不要再来骚扰我
* @author张飞:我发现我和大哥在一块,不是故事,就是事故。
*/
public classSmsShield extends Activity {
Button beginButton;
Button stopButton;
//SmsReceiver
SmsReceiver receiver = null;
//是否注册的标志位
boolean isRegisted = false;
//接收短信的action
staticfinal String ACTION = "android.provider.Telephony.SMS_RECEIVED";
@Override
public void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
beginButton =(Button)findViewById(R.id.beginButton);
stopButton =(Button)findViewById(R.id.stopButton);
beginButton.setEnabled(true);
stopButton.setEnabled(false);
// 开始拦截短信
beginButton.setOnClickListener(newOnClickListener() {
@Override
publicvoid onClick(View arg0) {
regist();
beginButton.setEnabled(false);
stopButton.setEnabled(true);
}
});
// 停止拦截短信
stopButton.setOnClickListener(newOnClickListener() {
@Override
public voidonClick(View arg0) {
unRegist();
}
});
}
// 在销毁的时候也要注销receiver
@Override
protected void onDestroy() {
super.onDestroy();
if (receiver != null &&isRegisted) {
unregisterReceiver(receiver);
isRegisted = false;
}
}
// 注册receiver
public void regist() {
IntentFilter filter = newIntentFilter(ACTION);
// 设置优先级最大
filter.setPriority(1000);
receiver = new SmsReceiver();
registerReceiver(receiver,filter);
isRegisted = true;
}
// 注销receiver
public void unRegist() {
if (receiver != null&& isRegisted) {
unregisterReceiver(receiver);
isRegisted = false;
}
}
}
在Android中短信是用有序广播的方式进行通知的,可以通过intent.setPriority(1000)将该程序设为最大优先级,先于其他程序获得短信广播。接收Broadcast的BroadcastReciever代码如下所示:
SmsReceiver代码清单11-4:
/**
* @author刘备至张飞短信:“呵呵,现在在干嘛呀?”
张飞:人在江湖飘,“呵呵”是把刀,有些“呵呵”的短信就是不能回。
*/
public class SmsReceiver extends BroadcastReceiver {
@Override
public voidonReceive(Context context, Intent intent) {
// 获得短信的内容
Object[] pdus =(Object[])intent.getExtras().get("pdus");
if (pdus != null&& pdus.length > 0) {
SmsMessage[] messages= new SmsMessage[pdus.length];
for (int i = 0; i< pdus.length; i++) {
byte[] pdu =(byte[])pdus[i];
messages[i] =SmsMessage.createFromPdu(pdu);
}
// 遍历新短信
for (SmsMessagemessage : messages) {
// 得到发信息的号码
String sender= message.getOriginatingAddress();
if(sender.equals("123456")) {
Toast.makeText(context, "讨厌,大哥又来骚扰我", 0).show();
// 中止发送
abortBroadcast();
}
}
}
}
}
上述代码通过调用abortBroadcast()方法终止有序广播的传播,使其他程序无法收到该广播。需要注意的是接收短信需要在manifest中加入android.permission.RECEIVE_SMS权限。
运行程序,结果如图11-1所示:
图片11-1 SmsShield界面
如果要使用静态注册Receiver则需要在manfiest中添加intent-filter,代码如下所示:
<receiverandroid:name=".SmsRecevier">
<!--将优先级设到最大 -->
<intent-filterandroid:priority="1000">
<actionandroid:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
孔明:一个Receiver也可以有多个intent-filter,那样就需要在onReceive()方法里对intent.getAction(action name)进行相应的判断。
刘备:如果两个Reciever的优先级一样时,顺序会怎样?
孔明:随机的。
刘备:原来如此!
关羽:军师,如何判断收到的广播是有序广播?
孔明:在Receiver中使用isOrderedBroadcast ()方法进行判断。
张飞:StickyBroadcast是什么
孔明:哇,真的假的,飞飞你这个问题问得好深邃啊!sendStickyBroadcast是Broadcast的一种发送方式。该Broadcast的最后一个Intent会被保留,当下次Recevier处于活动状态时,又会接收到保留的Intent。可以通过sendStickyBroadcast()方法进行发送,不过这时需要设置
孔明喝了口茶,道:“唉,这说的我口干舌燥,还好我智商够高,嘴皮够快,心肠够好,不然怎么教会你们呀。”
张飞接道:“军师的脸皮也够厚……”
还没等张飞说完,刘备随手拿起一个花盆就糊到张飞脸上!“三弟,不许侮辱军师!”
张飞扒掉脸上的土,抱怨道:“大哥,你咋对我脸意见这么大……”
刘备语重心长道:“唉,我这也是为你好呀,只有成为大牛才能赢得大家的尊重哇。”
孔明赶紧道:“翼德也是心直口快,没关系,对了,面试官都问了你啥?”
张飞歪了歪嘴,说:“别提了!一进去就看一壮汉翘个二郎腿在那嗑瓜子,爷爷我哪里还能看得下去,进去就是一招猴子偷桃攻他下盘,他一招仙人指路点我胸口。就这么我一招偷桃,他一招指路,我一招偷桃,他一招指路,打得好不欢乐。直到后来大哥叫我我这才走的,他还约我有时间再来打过,好像叫‘许猪’什么的。”
刘备、关羽、孔明三人听张飞说完,琢磨了好一会儿,也没能理解张飞是怎么个思想感情,为啥看人嗑瓜子就不爽了。
关羽摇了摇头道:“言归正传,我们还是太年轻了,还是应该多学学再去嚣张啊!这下倒好,尊严全无啊,以后还怎么在道上混啊。”
孔明说:“怕什么,这世上又不止曹操那一家的,而且你们的志向不是做出自己的产品吗?原来的骨气都哪去了?”
刘备说:“是呀!我们一定要做出比小曹还牛的产品,到时候威震四方,让小曹羡慕嫉妒恨去吧!”
孔明说:“我决定先对你们进行一个系统的集训,好好补一下Android的基本知识。嗯……首先就从Broadcast开始!”
1.1. Broadcast与BroadcastReceiver的关系
第九回提到了Intent在Broadcast中的作用,究竟什么是广播Broadcast?什么是广播接收器BroadcastReceiver?它们之间又是什么关系呢?本回将对Broadcast和BroadcastReceiver进行详细讲解。在Andoird中Broadcast是应用程序间传输消息的一种机制,通过Broadcast可以通知其他组件某个事件已经发生了,比如电量不足、wifi连接等,许多应用程序都可以接收Broadcast消息。Android的Broadcast机制主要由以下三部分组成:
l Broadcast:用于发送广播,即说明某件事情发生了,提醒相关的组件。
l BraodcastReceiver:用于接收广播,并进行相应处理。
l Intent:用于保存广播的相关信息(包括事件内容与用于过滤的信息)。
Broadcast的具体工作方式是这样的:在需要发送信息的地方,将需要发送的信息和用于过滤的信息(action、category等)装入一个Intent对象,然后调用Context.sendBroadcast()方法,将Intent对象发送出去。当Intent发送出去之后所有已经注册的BroadcastReceiver组件都会检测注册的intent-filter是否与该Intent相匹配,如果匹配则调用BroadcastReceiver的onReceive()方法,对Intent进行处理。
张飞:从上面的描述可以看出BroadcastReceiver也是一个卖烤串的,会对Broadcast发送的消息进行过滤,只关心能烤鸡翅什么的。 孔明:什么和什么,完全不能理解你的逻辑。 张飞:军师,我不明白Broadcast机制和前几回讲的Intent有什么区别? 孔明:你这个问题问得很好,其实……这根本就是两个东西!Broadcast是应用程序之间传递消息的一种机制,而Intent是消息的媒介。 |
1.2. Broadcast
在Android中Broadcast大体可以分为两类:普通广播和有序广播。普通广播是完全异步的,可以在同一时刻被所有接收者收到,消息传递的效率比较高,但缺点是接收者不能将处理结果传递给下一个接收者,且无法终止Intent的传播。有序广播则是按照接收者声明的优先级别,依次接收广播。例如,A的级别高于B,B的级别高于C,这时广播先传给A,再传给B,最后传给C。优先级别在intent-filter元素的priority属性中声明,取值范围是-1000到1000,数值越大级别越高。普通广播可使用Context.sendBroadcast()方法发送,有序广播可使用Context.sendOrederedBroadcast()方法进行发送。下面将要详细讲解Broadcast如何使用。1.2.1.发送Broadcast
军师,你看看下面我小飞飞写的Broadcast代码,那是典型的Broadcast示例代码:发送Broadcast代码清单11-2-1:
/**
* @author 刘备至张飞短信:“呵呵,干嘛呢?”
*/
publicclass SendBroadCastListener implements OnClickListener{
@Override
public void onClick(View arg0){
// intent就是我们要发送的内容
Intent intent = new Intent();
intent.putExtra("data", "broadcast”));
//设置你这个广播的action,
//BroadcastReciever的intent-filter会与action进行匹配,确定是否接收
intent.setAction(action);
//发送广播
sendBroadcast(intent);
}
}
1.2.2.Broadcast的action
在Android 中定义了许多action用于设置Broadcast,常用的action如表11-1所示:表11-1 Broadcast action
常量名 | 说明 |
ACTION_BOOT_COMPLETED | 在系统启动后,这个动作被广播一次(只有一次)。 |
ACTION_DATE_CHANGED | 日期被改变。 |
ACTION_PACKAGE_ADDED | 设备上安装了一个新的应用程序包。 |
ACTION_ SIG_STR | 信号强度已改变。 |
1.3. BroadcastReciever介绍
上一节介绍了Broadcast是如何发送的,本节将介绍BroadcastReceiver如何接收Broadcast。1.3.1.BroadcastReciever的实现
BroadcastReciever可以接收Broadcast的Intent。当特定的Broadcast发生是,就会触发BroadcastReceiver的onReceive()方法。//军师,我懂了,你再看看我小飞飞写的BroadcastReceiver实现,如何?
public class MyReceiverextends BroadcastReceiver {
@Override
//收到broadcast时会执行onReceive函数
public void onReceive(Context context, Intent intent) {
//显示出Toast
Toast.makeText(context,“The receiver of broadcast1 is started.. “).show();
}
}
1.3.2.BroadcastReciever的注册方式
BroadcastReceiver有两种注册方式:静态注册和动态注册。两种注册方式的区别是:动态注册的BroadcastReceiver不是常驻型的广播,BroadcastReceiver会随Activtiy的退出而注销;静态注册的BroadcastReceiver是常驻型的广播,当应用程序关闭后,如果有相应的Broadcast到来,程序也会被系统调用。下面详细讲解这两种注册方法:静态注册
在manifest中用<receiver>标签进行声明,并使用<intent-filter>标签注册过滤器,代码如下所示:
<receiverandroid:name=".SMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
动态注册
动态注册在代码中先定义并设置好一个IntentFilter对象,然后使用Context.registerReceiver()方法进行注册,如果BroadcastReceiver需要注销则调用Context.unregisterReceiver()方法,代码如下所示:
BroadcastReceiver的实现方法代码清单11-3-2:
/**
* @author 刘备至张飞短信:“呵呵,刚才在干嘛呢?”
*/
public class MyBroadcastReceiverextends Activity {
private BroadcastReceiver receiver;
//在Activity启动时注册一个BroadcastReceiver
@Override
protected void onStart() {
super.onStart();
//MyReceiver是一个自定义Receiver
receiver = new MyReceiver ();
//注册Receiver,并创建相应的IntentFilter对象
registerReceiver(receiver,
new IntentFilter("android.intent.action.PHONE_STATE"));
}
//在Activity停止时进行注销
@Override
protected void onStop() {
//注销
unregisterReceiver(receiver);
super.onStop();
}
}
孔明:需要特别注意的是,在退出程序前要记得调用Context.unregisterReceiver()方法。BroadcastReceiver一般在Activity的onStart()方法里进行注册,onStop()方法里进行注销。如果在Activity.onResume()方法里注册了BroadcastReceiver,就必须在Activity.onPause()方法里注销。 |
1.3.3.BroadcastReciever的生存周期
一个BroadcastReciever对象只有在调用onReceive(Context,Intent)方法后会进入活动状态,当从该方法返回后,进入失活状态。当BroadcastReciever处于活动状态时会被保护起来,而不会被杀死;当BroadcastReciever处于失活时,会在其他进程需要它所占有内存时随时被杀掉。如果响应一个广播信息需要较长的时间,为保证用户交互的流畅,可以将响应广播的操作放在一个线程中完成,而不是在主线程中完成。孔明:在onReceiver()中不应做非常耗时的操作,比如准备SD卡、上传图片、读取数据库等。一个基本的规则就是:快速响应,然后返回。 |
1.4. Broadcast的使用
张飞最近被刘备的蹭饭短信骚扰的无可奈何。这几天听说Android中是以广播的形式接收短信的,他决定写一个程序彻底改善自己的生活。他编写了一个Activity类,命名为SmsShield,代码如下所示:SmsShield代码清单11-4-0:
/**
* 动态注册BroadcastReceiver
* ——大哥,不要再来骚扰我
* @author张飞:我发现我和大哥在一块,不是故事,就是事故。
*/
public classSmsShield extends Activity {
Button beginButton;
Button stopButton;
//SmsReceiver
SmsReceiver receiver = null;
//是否注册的标志位
boolean isRegisted = false;
//接收短信的action
staticfinal String ACTION = "android.provider.Telephony.SMS_RECEIVED";
@Override
public void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
beginButton =(Button)findViewById(R.id.beginButton);
stopButton =(Button)findViewById(R.id.stopButton);
beginButton.setEnabled(true);
stopButton.setEnabled(false);
// 开始拦截短信
beginButton.setOnClickListener(newOnClickListener() {
@Override
publicvoid onClick(View arg0) {
regist();
beginButton.setEnabled(false);
stopButton.setEnabled(true);
}
});
// 停止拦截短信
stopButton.setOnClickListener(newOnClickListener() {
@Override
public voidonClick(View arg0) {
unRegist();
}
});
}
// 在销毁的时候也要注销receiver
@Override
protected void onDestroy() {
super.onDestroy();
if (receiver != null &&isRegisted) {
unregisterReceiver(receiver);
isRegisted = false;
}
}
// 注册receiver
public void regist() {
IntentFilter filter = newIntentFilter(ACTION);
// 设置优先级最大
filter.setPriority(1000);
receiver = new SmsReceiver();
registerReceiver(receiver,filter);
isRegisted = true;
}
// 注销receiver
public void unRegist() {
if (receiver != null&& isRegisted) {
unregisterReceiver(receiver);
isRegisted = false;
}
}
}
在Android中短信是用有序广播的方式进行通知的,可以通过intent.setPriority(1000)将该程序设为最大优先级,先于其他程序获得短信广播。接收Broadcast的BroadcastReciever代码如下所示:
SmsReceiver代码清单11-4:
/**
* @author刘备至张飞短信:“呵呵,现在在干嘛呀?”
张飞:人在江湖飘,“呵呵”是把刀,有些“呵呵”的短信就是不能回。
*/
public class SmsReceiver extends BroadcastReceiver {
@Override
public voidonReceive(Context context, Intent intent) {
// 获得短信的内容
Object[] pdus =(Object[])intent.getExtras().get("pdus");
if (pdus != null&& pdus.length > 0) {
SmsMessage[] messages= new SmsMessage[pdus.length];
for (int i = 0; i< pdus.length; i++) {
byte[] pdu =(byte[])pdus[i];
messages[i] =SmsMessage.createFromPdu(pdu);
}
// 遍历新短信
for (SmsMessagemessage : messages) {
// 得到发信息的号码
String sender= message.getOriginatingAddress();
if(sender.equals("123456")) {
Toast.makeText(context, "讨厌,大哥又来骚扰我", 0).show();
// 中止发送
abortBroadcast();
}
}
}
}
}
上述代码通过调用abortBroadcast()方法终止有序广播的传播,使其他程序无法收到该广播。需要注意的是接收短信需要在manifest中加入android.permission.RECEIVE_SMS权限。
运行程序,结果如图11-1所示:
图片11-1 SmsShield界面
如果要使用静态注册Receiver则需要在manfiest中添加intent-filter,代码如下所示:
<receiverandroid:name=".SmsRecevier">
<!--将优先级设到最大 -->
<intent-filterandroid:priority="1000">
<actionandroid:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
1.5. 玄德有话说
刘备:孔明啊,一个Receiver是否可以接收多个Broadcast?孔明:一个Receiver也可以有多个intent-filter,那样就需要在onReceive()方法里对intent.getAction(action name)进行相应的判断。
刘备:如果两个Reciever的优先级一样时,顺序会怎样?
孔明:随机的。
刘备:原来如此!
关羽:军师,如何判断收到的广播是有序广播?
孔明:在Receiver中使用isOrderedBroadcast ()方法进行判断。
张飞:StickyBroadcast是什么
孔明:哇,真的假的,飞飞你这个问题问得好深邃啊!sendStickyBroadcast是Broadcast的一种发送方式。该Broadcast的最后一个Intent会被保留,当下次Recevier处于活动状态时,又会接收到保留的Intent。可以通过sendStickyBroadcast()方法进行发送,不过这时需要设置
BROADCAST_STICKY权限才行。
相关文章推荐
- 关于测试人员的职业发展
- Codeforces Round #278 (Div. 1) A. Fight the Monster 暴力
- Thread系列——Thread.Sleep(0)
- 你不知道的JavaScript--Item32 DOM基础详解2
- Could not load the "*.png" image referenced from a nib in the bundle with identifier
- Linux GPIO驱动 - 驱动框架概述
- Ubuntu 14.04.3 LTS如何安装谷歌输入法
- Maven多环境配置实战 Filter
- Ubuntu 14.04.3 LTS如何安装谷歌输入法
- Ubuntu 14.04.3 LTS如何安装谷歌输入法
- 如何消除类型是submit类型的按钮的默认文字 ‘确认提交’
- Zabbix 实现微信短信告警
- cocos2d-x mruby学习笔记--扩展2(mruby code)
- 028 - Implement strStr()
- 怎么区分五类线、超五类线和六类线
- 关于svn使用cornerstone时,有时会出现无法提.a或其他文件,导致报错
- 程序员的1111
- 从win7到mac os再到win10,体验总结
- 【Android入门】——模拟器的创建及常见问题汇总
- Git的基本命令及原理