Android Broadcast详解
活动(Activity) - 用于表现功能
服务(Service) - 相当于后台运行的 Activity
广播(Broadcast) - 用于发送广播
广播接收器(BroadcastReceiver) - 用于接收广播
Intent - 用于连接以上各个组件,并在其间传递消息
BroadcastReceiver是一种全局的监听器,用于监听全局广播消息,可以方便实现不同组件之间的通信。其用于接收广播通知信息,并做出对应处理的组件。很多广播是源自于系统代码的 ── 比如,通知时区改变、电池电量低、拍摄一张照片或者用户改变了语言选项。应用程序也可以进行广播 ── 比如说,通知其它应用程序一些数据下载完成并处于可用状态。 应用程序可以拥有任意数量的广播接收器以对所有它感兴趣的通知信息予以响应。所有的接收器均继承自BroadcastReceiver基类。 广播接收器没有用户界面。然而,其可以启动一个Activity来响应它们收到的信息,或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力,如闪动背灯、震动、播放声音等等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。
(1)继承 BroadcastReceiver类,并重写onReceive()方法
publicclassIncomingSMSReceiverextendsBroadcastReceiver{
@OverridepublicvoidonReceive(Contextcontext,Intentintent){
}
}
(2)注册广播的方法有两种
IntentFilterfilter=new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
IncomingSMSReceiverreceiver=newIncomingSMSReceiver();
registerReceiver(receiver,filter);
注:一般在onStart中注册,onStop中取消unregisterReceiver
2>在AndroidManifest.xml文件中的<application>节点里进行订阅:
<receiverandroid:name=".IncomingSMSReceiver">
<intent-filter>
<actionandroid:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
首先在需要发送信息的地方,把要发送的信息和用于过滤的信息(如Action、Category)装入一个Intent对象,然后通过调用 Context.sendBroadcast()、sendOrderBroadcast()或sendStickyBroadcast()方法,把 Intent对象以广播方式发送出去
当Intent发送以后,所有已经注册的BroadcastReceiver会检查注册时的IntentFilter是否与发送的Intent相匹配,若 匹配则就会调用BroadcastReceiver的onReceive()方法。所以当我们定义一个BroadcastReceiver的时候,都需要 实现onReceive()方法
广播被分为两种不同的类型
(1)普通广播(Normalbroadcasts):完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播 (2)粘性广播(Sticky broadcast):该种发送并经过AMS(ActivityManagerService)分发给对应的receiver后,这个broadcast并不会被丢弃,而是保存在AMS中,当有新的需要动态注册的receiver请求AMS注册时,如果这个receiver能够接收这个broadcast,那么AMS会将在receiver注册成功之后,马上向receiver发送这个broadcast。使用sendStickyBroadcast()来发送该种属性广播,使用这个api需要权限 android.Manifest.permission.BROADCAST_STICKY,粘性广播的特点是Intent会一直保留到广播事件结束,而这种广播也没有所谓的10秒限制,10秒限制是指普通的广播如果onReceive方法执行时间太长,超过10秒的时候系统会将这个广播置为可以干掉的candidate,一旦系统资源不够的时候,就会干掉这个广播而让它不执行 (3)有序广播(Orderedbroadcasts):按照接收者声明的优先级别,被接收者依次接收广播。如:A的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C。优先级别声明在intent-filter元素的android:priority属性中,数越大优先级别越高,取值范围:-1000到1000,优先级别也可以调用IntentFilter对象的setPriority()进行设置。有序广播的接收者可以终止广播Intent的传播,广播Intent的传播一旦终止,后面的接收者就无法接收到广播。前面的接收者可以对广播的内容进行修改,修改的结果被后面接收者接收,优先级高的接收者还可以结束这个广播 注:有序广播的接收者可以将数据传递给下一个接收者,如:A得到广播后,可以往它的结果对象中存入数据,当广播传给B时,B可以从A的结果对象中得到A存入的数据
指定广播目标Action:Intent Intent = new Intent(action-String)
指定了此action的receiver会接收此广播
需传递参数(可选) putExtra();
发送:sendBroadcast(Intent);
(1)Context.sendBroadcast():发送的是普通广播,所有订阅者都有机会获得并进行处理
(2)Context.sendOrderedBroadcast():发送的是有序广播,系统会根据接收者声明的优先级别按顺序逐个执行接收者
广播接收器的分类 1> 私有广播接收器:只接收app自身发出的广播 2> 公共广播接收器:能接收所有app发出的广播 3> 内部广播接收器:只接收内部app发出的广播 intent-filter节点与exported属性设置组合建议
(1)私有广播接收器设置exported='false',并且不配置intent-filter。(私有广播接收器依然能接收到同UID的广播) <receiver android:name=".PrivateReceiver" android:exported="false" /> (2)对接收来的广播进行验证 (3)内部app之间的广播使用protectionLevel='signature'验证其是否真是内部app (4)返回结果时需注意接收app是否会泄露信息 (5)发送的广播包含敏感信息时需指定广播接收器,使用显示意图或者 setPackage(String packageName) (6)sticky broadcast粘性广播中不应包含敏感信息 (7)Ordered Broadcast建议设置接收权限receiverPermission,避免恶意应用设置高优先级抢收此广播后并执行abortBroadcast()方法 注:使用 LocalBroadcastManager.sendBroadcast() 发出的广播只能被app自身广播接收器接收 Intent intent = new Intent("my-sensitive-event"); intent.putExtra("event", "this is a test event"); LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
系统收到短信,发出的广播属于有序广播。如果想阻止用户收到短信,可以通过设置优先级,让你们自定义的接收者先获取到广播,然后终止广播,这样用户就接收不到短信了
如:
publicclassIncomingSMSReceiverextendsBroadcastReceiver{
privatestaticfinalStringSMS_RECEIVED="android.provider.Telephony.SMS_RECEIVED";
@Override
publicvoidonReceive(Contextcontext,Intentintent){
if(intent.getAction().equals(SMS_RECEIVED)){
SmsManagersms=SmsManager.getDefault();
Bundlebundle=intent.getExtras();
if(bundle!=null){
Object[]pdus=(Object[])bundle.get("pdus");
SmsMessage[]messages=newSmsMessage[pdus.length];
for(inti=0;i<pdus.length;i++)
messages[i]=SmsMessage.createFromPdu((byte[])pdus[i]);
for(SmsMessagemessage:messages){
Stringmsg=message.getMessageBody();
Stringto=message.getOriginatingAddress();
sms.sendTextMessage(to,null,msg,null,null);
}
}
}
}
}
在AndroidManifest.xml文件中的<application>节点里对接收到短信的广播Intent进行订阅:
<receiverandroid:name=".IncomingSMSReceiver">
<intent-filter>
<actionandroid:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
在AndroidManifest.xml文件中添加以下权限:
<uses-permissionandroid:name="android.permission.RECEIVE_SMS"/><!--接收短信权限-->
<uses-permissionandroid:name="android.permission.SEND_SMS"/><!--发送短信权限-->
在Android中,每次广播消息到来时都会创建BroadcastReceiver实例并执行onReceive()方法,onReceive()方法执行完后,BroadcastReceiver的实例就会被销毁。
注:当 onReceive() 方法在10秒内没有执行完毕,Android会认为该程序无响应。所以在 BroadcastReceiver 里不能做一些比较耗时的操作,否侧会弹出ANR(ApplicationNoResponse)的对话框。如果需要完成一项比较耗时的工作,应该通过发送 Intent 给 Service ,由 Service 来完成。这里不能使用子线程来解决,因为 BroadcastReceiver 的生命周期很短,子线程可能还没有结束 BroadcastReceiver 就先结束了。 BroadcastReceiver 一旦结束,此时 BroadcastReceiver 的所在进程很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程)。如果它的宿主进程被杀死,那么正在工作的子线程也会被杀死。所以采用子线程来解决是不可靠的如:
publicclassIncomingSMSReceiverextendsBroadcastReceiver{
@Override
publicvoidonReceive(Contextcontext,Intentintent){
//发送Intent启动服务,由服务来完成比较耗时的操作
Intentservice=newIntent(context,XxxService.class);
context.startService(service);
}
}
广播接收者
除了短信到来广播Intent,Android还有很多广播Intent,如:开机启动、电池电量变化、时间已经改变等广播Intent。
(1)接收电池电量变化广播Intent
在AndroidManifest.xml文件中的<application>节点里订阅此Intent
<receiverandroid:name=".IncomingSMSReceiver">
<intent-filter>
<actionandroid:name="android.intent.action.BATTERY_CHANGED"/>
</intent-filter>
</receiver>
(2)接收开机启动广播Intent
在AndroidManifest.xml文件中的<application>节点里订阅此Intent
<receiverandroid:name=".IncomingSMSReceiver">
<intent-filter>
<actionandroid:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
并且要进行权限声明:
<uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
(3)接收短信广播Intent
在AndroidManifest.xml文件中的<application>节点里订阅此Intent
<receiverandroid:name=".IncomingSMSReceiver">
<intent-filter>
<actionandroid:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
在AndroidManifest.xml文件中添加以下权限
<uses-permissionandroid:name="android.permission.RECEIVE_SMS"/><!--接收短信权限-->
<uses-permissionandroid:name="android.permission.SEND_SMS"/><!--发送短信权限-->
无序广播的发送和接收实例
1>创建广播接收函数需要继承于BroadcastReceiver
importandroid.content.BroadcastReceiver;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.util.Log;
importandroid.widget.Toast;
publicclassMyReceiverextendsBroadcastReceiver{
@Override
publicvoidonReceive(Contextcontext,Intentintent){
Log.i("MyReceiver.onReceive","进入广播处理函数!Action="+intent.getAction());
if("HEHE.HAHA".equals(intent.getAction())){
Toast.makeText(context,"收到的Action为:"+intent.getAction()+"\n收的到内容是:"
+intent.getStringExtra("msg"),Toast.LENGTH_SHORT).show();
Log.i("MyReceiver.onReceive","进入广播处理函数的里面!");
}
}
}
2>在<application>中注册BroadcastReceiver
<!--注册BroadcastReciver-->
<receiverandroid:name="com.example.mybroadcast.MyReceiver">
<intent-filter>
<actionandroid:name="HEHE.HAHA"/>
</intent-filter>
</receiver>
3>发送广播
importandroid.os.Bundle;
importandroid.app.Activity;
importandroid.content.Intent;
importandroid.util.Log;
importandroid.view.Menu;
importandroid.view.View;
importandroid.widget.Button;
publicclassMainActivityextendsActivity{
}privateButtonbutton;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//按钮处理方法
publicvoidonReceive(Viewview){
Log.i("MainActivity.onReceive","进入onReceive");
Intentintent=newIntent();
intent.setAction("HEHE.HAHA");
intent.putExtra("msg","简单的消息!");
//发送广播
sendBroadcast(intent);
}
更多相关文章
- 【更新】Google 与微软开始口水战
- 微软一年通过Android获得几十亿美元收入,没错,是微软!
- Android 广播接收者(具体例子)
- 不仅是微软和诺基亚,谁都无法 fork Android,因为它就没法 fork
- 关于android的广播接收器(1)—基础篇
- Android:微软的金钱机器(更新)
- 五成Android设备要向微软支付专利费