大家好,今天来为大家解答在BroadcastReceiver中安全执行长时间操作的最佳实践这个问题的一些问题点,包括也一样很多人还不知道,因此呢,今天就来为大家分析分析,现在让我们一起来看看吧!如果解决了您的问题,还望您关注下本站哦,谢谢~
一、BroadcastReceiver 注册方式
BroadcastReceiver有两种注册方式,一种是使用{Context.registerReceiver()}动态注册,另一种是通过AndroidManifest.xml中的元素静态注册。
笔记:
如果您在Activity 的onResume() 方法中注册了广播,则需要在onPause() 方法中取消注册它。当Activity处于暂停状态时,将不会收到广播。一般在onCreate()方法中注册,在onDestroy()方法中注销。
1、安全性
由于Intent的命名空间是全局的,因此需要保证Intent的action唯一,否则会与其他应用冲突。使用Context.registerReceiver()时,任何应用程序都可以向注册的接收者发送广播,可以通过为广播添加权限来控制接收者。当在AndroidManifest.xml 中静态注册广播并澄清意图过滤器时,任何应用程序都可以忽略意图过滤器并向您发送广播。您可以设置android:exported="false"。为了解决上述问题,本应用程序的广播可以被其他应用程序接收。一个好的方法是使用本地广播LocalBroadcastManager,这样发送的意图只能由该应用程序接收。
2、进程生命周期
如果一个进程正在执行BroadcastReceiver的onReceive()方法,它将被视为前台进程,不会轻易被系统杀死。
当执行onReceive()时,BroadcastReceiver不再处于活动状态,其进程将被系统视为空进程,并且随时可能被系统杀死。
3、Receiver 生命周期
BroadcastReceiver的生命周期很短。从onReceiver()方法的开始到结束都是有效的。之后,系统将销毁BroadcastReceiver对象。因此,如果在onReceive方法中进行异步请求操作,很有可能不会返回请求结果,BroadcastReceiver就会被系统回收。
通过上述,可知如何正确地使用BroadcastReceiver:
如果要在BroadcastReceiver中执行耗时的操作,创建子线程是不可靠的,因为BroadcastReceiver的生命周期很短。一旦结束,它所在的进程就是一个空进程(没有任何活动组件的进程)。当系统内存不足时,很容易首先被杀死。在这种情况下,工作子线程也会被杀死。要在BroadcastReceiver中进行耗时的操作,可以开启一个Service,并将耗时的操作交给Service。这样可以提高宿主进程的优先级,保证耗时的操作完成。不建议在BroadcastReceiver中显示Dialog。如果要弹出对话框,可以将其设为全局对话框,并声明SYSTEM_ALERT_WINDOW权限;你不能bindService,因为bindService 绑定器与调用者在一起。一旦调用者退出,服务就会停止。
二、如何在BroadcastReceiver中执行耗时操作
在Android开发中,一般耗时的操作都会尽可能的留给Service,比如上传图片。由于应用程序在上传过程中可能会被置于后台,因此Activity可能会被系统回收。如果担心Service被回收,也可以通过startForeground(int,Notification)提高其优先级。
我们知道Service工作在主线程,所以不能直接在其中执行耗时的操作。一般需要开子线程来做。 IntentService是Service的子类,可以用来处理异步请求。与服务相同。好处有两个:一是它内部开启了一个异步处理工作线程HandlerThread,所以我们不需要自己去new Thread;其次,不需要考虑何时关闭Service,当所有任务完成后它会自动关闭。
注:IntentService执行流程简单说明:
HandlerThread是Thread的子类。与普通线程相比,会创建一个Looper,线程会有一个MessageQueue,然后就会陷入死循环。这个Looper对象将会用来创建一个Handler,这样它就可以一直访问这个线程的消息队列。获取Message消息并进行处理。 Handler的创建是在IntentService中完成的。在IntentService的onCreate()方法中,首先会打开HandlerThread异步消息处理线程,然后获取该线程的Looper对象来创建Handler。每次startService()时,如果IntentService还有未处理的消息,则只会执行onStartCommand(Intent, int, int startId);方法。在该方法中,参数Intent和startId会通过handler封装成一个Message。 sendMessage()方法发送到消息队列。 Handler的handleMessgae()消息处理方法执行两个步骤:首先,它提供回调方法来获取外部参数,以进行耗时操作。用户可以定制;其次,当消息队列为空时,通过Message中封装的startId停止IntentService。 【注:此时的Handler处理消息是在HandleThread子线程中处理的,因为是通过子线程的looper创建的,与主线程无关。 ]
接下来看一个在BroadcastReceiver中使用IntentService执行耗时操作的完整示例。
三、实例代码
主线程代码部分:
公共类BroadcastTestActivity 扩展AppCompatActivity 实现View.OnClickListener {
公共静态最终字符串标记="主线程";
公共静态最终字符串ACTION_SEND_MSG_BY_MYINTENTSERVICE="com.xss.download.by.myIntentService";
公共静态最终字符串ACTION_FROM_INTENTSERVICE="com.xss.download.intentService";
私有按钮btn_send_intent_service;
私有TextView tv_msg,tv_msg_intent_service;
private DownloadBroadcastReceiver downloadBroadcastReceiver;
//最好使用本地广播LocalBroadcast
类DownloadBroadcastReceiver 扩展BroadcastReceiver {
@覆盖
公共无效onReceive(上下文上下文,意图意图){
//跳过5999 帧!目前仅提示丢帧,不会出现ANR弹窗。
//SystemClock.sleep(100000);
tv_msg.append("--onReceive: action=" + Intent.getAction());
tv_msg.append("n");
字符串数据=Intent.getStringExtra("data");
//3. 执行耗时操作
如果(ACTION_SEND_MSG_BY_MYINTENTSERVICE.equals(intent.getAction())){
tv_msg_intent_service.append("--onReceiver:通过IntentService处理耗时!");
tv_msg_intent_service.append("n");
//方法二:使用IntentService处理耗时操作,通过广播回调处理成功回调
sendMsgByIntentService(上下文,数据);
} else if (ACTION_FROM_INTENTSERVICE.equals(intent.getAction())) {
//方法二回调结果:Service通过广播发送数据并更新UI
tv_msg_intent_service.append("n");
tv_msg_intent_service.append("--onReceiver:从IntentService接收到数据!");
tv_msg_intent_service.append("n");
tv_msg_intent_service.append("--data=" + intent.getStringExtra("data_from_intent_service"));
tv_msg_intent_service.append("n");
}
}
}
/**
* 策略2:使用IntentService进行处理
* @参数数据
*/
私有无效sendMsgByIntentService(上下文上下文,字符串数据){
Intent意图=new Intent(context, MyIntentService.class);
Intent.setAction("com.xss.startIntentService");
Intent.putExtra("数据", 数据);
context.startService(意图);
}
@覆盖
protected void onCreate(Bundle savingInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast_test);
//1.注册广播
注册广播();
初始化视图();
}
私有无效registerBroadcast(){
downloadBroadcastReceiver=new DownloadBroadcastReceiver();
IntentFilter IntentFilter=new IntentFilter("");
IntentFilter.addAction(ACTION_SEND_MSG_BY_MYHANDLERTHREAD);
intentFilter.addAction(ACTION_SEND_MSG_BY_MYINTENTSERVICE);
intentFilter.addAction(ACTION_FROM_INTENTSERVICE);
registerReceiver(downloadBroadcastReceiver,intentFilter);
}
私有无效initView() {
tv_msg=(TextView) findViewById(R.id.tv_msg);
tv_msg_handler_thread=(TextView) findViewById(R.id.tv_msg_handler_thread);
btn_send_my_handler_thread=(按钮) findViewById(R.id.btn_send_my_handler_thread);
tv_msg_intent_service=(TextView) findViewById(R.id.tv_msg_intent_service);
btn_send_intent_service=(按钮) findViewById(R.id.btn_send_intent_service);
btn_send_my_handler_thread.setOnClickListener(this);
btn_send_intent_service.setOnClickListener(this);
}
私人无效sendBroadcast(字符串动作){
//2.发送广播
意图意图=新意图(动作);
Intent.putExtra("data", "你好,这是广播发送给您的一条消息!");
发送广播(意图);
}
@覆盖
公共无效onClick(查看v){
开关(v.getId()) {
案例R.id.btn_send_intent_service:
tv_msg_intent_service.append("--onClick:开始发送广播!--n");
发送广播(ACTION_SEND_MSG_BY_MYINTENTSERVICE);
休息;
默认:
休息;
}
}
@覆盖
受保护无效onDestroy() {
super.onDestroy();
取消注册接收器(下载广播接收器);
stopService(新的意图());
}
}对于自定义IntentService,只需继承IntentSerive并重写其onHandleIntent()方法即可。代码如下:
//该方法是从HandlerThread异步消息处理线程的消息队列中取出消息进行处理。当所有消息处理完毕且messageQueue为空时,IntentService会调用stopSelf方法停止。
@覆盖
protected void onHandleIntent(@Nullable Intent 意图) {
Log.d(TAG, "IntentService 正在处理意图消息");
if ("com.xss.startIntentService".equals(intent.getAction())) {
String msg=Intent.getStringExtra("data");
Log.d(TAG, Thread.currentThread().getName());
Log.d(TAG, "从主处理程序线程:收到的消息广播发送=" + msg);
//处理耗时的请求
系统时钟.睡眠(5000);
Log.d(TAG, "广播是否ANR?");
//子线程处理完消息后,向主线程发送消息说‘我已经执行完毕’
消息mainMsg=new Message();
mainMsg.what=0x22;
mainMsg.obj="来自子处理程序thread: 的消息我已经完成了!";
//使用广播将数据处理耗时操作发送到主线程
意图intent0=new Intent(BroadcastTestActivity.ACTION_FROM_INTENTSERVICE);
intent0.putExtra("data_from_intent_service", "来自MyIntentService: 的消息我已完成!");
发送广播(意图0);
//如果消息队列为空,则直接终止Service,然后执行onDestroyed方法。
}
【在BroadcastReceiver中安全执行长时间操作的最佳实践】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
之前遇到过这个烦恼,广播接受者执行耗时长操作卡顿真的烦!
有16位网友表示赞同!
这篇文章说的对!不能阻塞主线程啊,不然程序就僵住了。
有17位网友表示赞同!
了解一下~我最近也在研究BroadcastReceiver,感谢分享这篇教程!
有13位网友表示赞同!
异步线程真是个好方法,可以保证用户体验...
有8位网友表示赞同!
有时候广播接收者确实需要处理一些耗时的任务,这个问题很重要啊!
有14位网友表示赞同!
学习新技能总是很有趣的,这次有机会能学到关于BroadcastReceiver的知识!
有10位网友表示赞同!
我最近也在项目里用到BroadcastReceiver,这个分享太棒了!
有11位网友表示赞同!
原来还有这么个方法处理耗时操作,受益匪浅!
有8位网友表示赞同!
这篇教程讲得很清楚,可以让我更好地理解BroadcastReceiver的使用场景。
有17位网友表示赞同!
我要去试试看,看看把耗时操作放到后台能不能改善用户体验!
有18位网友表示赞同!
我对Android开发还在探索阶段,这种技术分享真的非常赞助学习!
有14位网友表示赞同!
感谢作者的细心讲解,让我明白怎么处理BroadcastReceiver中的耗时任务!
有16位网友表示赞同!
这个技巧真神,以后遇到类似问题可以直接参考!
有8位网友表示赞同!
我的开发水平还得提高,但我会努力学习这些新的知识和方法。
有7位网友表示赞同!
Android开发的乐趣就在于不断挑战和学习新技术!
有17位网友表示赞同!
这个分享很实用,我一定会在今后的开发中应用起来!
有18位网友表示赞同!
希望以后能看到更多关于BroadcastReceiver的文章和教程!
有8位网友表示赞同!
文章内容简单易懂,适合新手学习。感谢作者的分享!
有16位网友表示赞同!
我很喜欢这种深入浅出的讲解方式!
有17位网友表示赞同!
我是一个Android开发爱好者,希望能学习到更多有价值的技术!
有20位网友表示赞同!
BroadcastReceiver确实是个强大的工具,通过了解它的使用方法,可以开发更强大的应用!
有6位网友表示赞同!