Android大量使用了Broadcast Receiver来广播系统事件,如网络连接、扩展dock状态及来电的变化。
一、注意:
android 中service和broadcastreceiver都是运行在主UI线程中,如果在他们中执行耗时操作,若果操作持续的时间超过android平台的约定,那么android平台会认为该程序出现异常,从而抛出ANR异常。如果在onReceive()的处理中,用户进行了UI触发,将可能引发ANR异常,不过和activity的时间限制不同,receiver在10秒而非5秒后触发ANR。
处理耗时的Broadcast Receiver时,一般采用的做法是将其置于一个Service中:(也可以通过在程序中使用registerReceiver(receiver, filter, broadcastPermission, scheduler)方法中的最后一个参数指定要运行的广播接收器的线程。)
1、在广播receiver的onReceive()中获取static的wake lock,静态是为了在广播接收器和service之间通信。因为service没有什么其他法将一个wake lock对象传递到service中。
2、开启local service使得进程不被终结。
3、在service中开启一个worker线程来进行处理。
4、当worker线程处理完,要通知service结束,可以直接stop(),或者通过Handler在主线程中结束service。
5、service要关闭静态的wake lock
二、BrocastReceiver用法:
1、继承BroadcastReceiver类,重写其onReceive函数:
/** 自定义BroadcastReceiver,只需重写其onReceive函数即可**/ public class TestBroadcastReceiver extends BroadcastReceiver{ public static final String ACTION = "com.TestBroadcastReceiver"; /** receiver接收到消息后的响应*/ @Override public void onReceive(Context context, Intent intent) { // @value String TEXT_EXTRA = "TEXT_EXTRA"; String reString = intent.getStringExtra(MainActivity.TEXT_EXTRA); Toast.makeText(context, reString, Toast.LENGTH_SHORT).show(); } }
2、可以选择在代码中动态注册BroadcastReceiver,也可以在Manifest中注册全局BroadcastReceiver
(1)在manifest中注册receiver
<!-- 注意要放在application中 --> <!-- 在manifest中注册receiver--> <receiver android:name=".TestBroadcastReceiver" android:permission="TestBroadcastReceiver"> <intent-filter> <action android:name="com.TestBroadcastReceiver"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </receiver>
private IntentFilter intentFilter; private TestBroadcastReceiver receiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intentFilter = new IntentFilter(TestBroadcastReceiver.ACTION); receiver = new TestBroadcastReceiver(); } @Override public void onResume(){ super.onResume(); // 注册receiver registerReceiver(receiver, intentFilter); } @Override public void onPause(){ // 注销receiver unregisterReceiver(receiver); super.onPause(); }
3、发送Intent消息
// 发送Intent信息,以便BrocastReceiver接收 Intent intent = new Intent(TestBroadcastReceiver.ACTION); // @value String ACTION = "com.TestBroadcastReceiver"; intent.putExtra(TEXT_EXTRA, "Send Message"); // @value String TEXT_EXTRA = "TEXT_EXTRA" // 发送Intent消息 sendBroadcast(intent);
三、Local Broadcast Manager(局部广播管理器)
// 单例模式获取实例 LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this); // 自定义BroadcastReceiver BroadcastReceiver broadcastReceiver = new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { }}; // 注册receiver lbm.registerReceiver(broadcastReceiver, new IntentFilter(TestBroadcastReceiver.ACTION)); // 发送Intent消息 lbm.sendBroadcast(new Intent(TestBroadcastReceiver.ACTION)); // 注销receiver lbm.unregisterReceiver(broadcastReceiver);
四、相关面试题
答:首先写一个类要继承BroadcastReceiver
第一种:在清单文件中声明receiver
第二种使用代码进行注册registerReceiver
两种注册类型的区别是:
1)第一种是常驻型(静态注册),也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
2)第二种不是常驻型广播(动态注册),也就是说广播跟随程序的生命周期。
优缺点:
动态注册优点:在 Android 的广播机制中,动态注册的优先级是要高于静态注册优先级的,因此在必要的情况下,我们是需要动态注册广播接收器的。
2、Android引入广播机制的用意?
答:a:从MVC的角度考虑(应用程序内)
其实回答这个问题的时候还可以这样问,android为什么要有那4大组件,现在的移动开发模型基本上也是照搬的web那一套MVC架构,只不过是改了点嫁妆而已。android的四大组件本质上就是为了实现移动或者说嵌入式设备上的MVC架构,它们之间有时候是一种相互依存的关系,有时候又是一种补充关系,引入广播机制可以方便几大组件的信息和数据交互。
b:程序间互通消息(例如在自己的应用程序内监听系统来电)
c:效率上(参考UDP的广播协议在局域网的方便性)
d:设计模式上(反转控制的一种应用,类似监听者模式)
3、解释一下activity、 intent 、intent filter、service、Broadcase、BroadcaseReceiver
答:
一个activity呈现了一个用户可以操作的可视化用户界面
一个service不包含可见的用户界面,而是在后台运行,可以连接到一个正在运行的服务中,连接后,可以通过服务中暴露出来的借口与其进行通信
一个broadcast receiver是一个接收广播消息并作出回应的component,broadcast receiver没有界面
content provider在接收到ContentResolver的请求时被激活。
activity, service和broadcast receiver是被称为intents的异步消息激活的。
一个intent是一个Intent对象,它保存了消息的内容。对于activity和service来说,它指定了请求的操作名称和待操作数据的URI
Intent对象可以显式的指定一个目标component(组件)。如果这样的话,android会找到这个component(基于manifest文件中的声明)并激活它。但如果一个目标不是显式指定的,android必须找到响应intent的最佳component。
它是通过将Intent对象和目标的intent filter相比较来完成这一工作的。一个component的intent filter告诉android该component能处理的intent。intent filter也是在manifest文件中声明的。