您的位置:首页 > 其它

第11回 我猜小曹不会用Broadcast

2015-11-11 18:38 232 查看
刘关张听完孔明的讲解之后,恍然大悟,深感Service的博大精深。

孔明喝了口茶,道:“唉,这说的我口干舌燥,还好我智商够高,嘴皮够快,心肠够好,不然怎么教会你们呀。”

张飞接道:“军师的脸皮也够厚……”

还没等张飞说完,刘备随手拿起一个花盆就糊到张飞脸上!“三弟,不许侮辱军师!”

张飞扒掉脸上的土,抱怨道:“大哥,你咋对我脸意见这么大……”

刘备语重心长道:“唉,我这也是为你好呀,只有成为大牛才能赢得大家的尊重哇。”

孔明赶紧道:“翼德也是心直口快,没关系,对了,面试官都问了你啥?”

张飞歪了歪嘴,说:“别提了!一进去就看一壮汉翘个二郎腿在那嗑瓜子,爷爷我哪里还能看得下去,进去就是一招猴子偷桃攻他下盘,他一招仙人指路点我胸口。就这么我一招偷桃,他一招指路,我一招偷桃,他一招指路,打得好不欢乐。直到后来大哥叫我我这才走的,他还约我有时间再来打过,好像叫‘许猪’什么的。”

刘备、关羽、孔明三人听张飞说完,琢磨了好一会儿,也没能理解张飞是怎么个思想感情,为啥看人嗑瓜子就不爽了。

关羽摇了摇头道:“言归正传,我们还是太年轻了,还是应该多学学再去嚣张啊!这下倒好,尊严全无啊,以后还怎么在道上混啊。”

孔明说:“怕什么,这世上又不止曹操那一家的,而且你们的志向不是做出自己的产品吗?原来的骨气都哪去了?”

刘备说:“是呀!我们一定要做出比小曹还牛的产品,到时候威震四方,让小曹羡慕嫉妒恨去吧!”

孔明说:“我决定先对你们进行一个系统的集训,好好补一下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
权限才行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: