欢迎来真孝善网,为您提供真孝善正能量书籍故事!

在BroadcastReceiver中安全执行长时间操作的最佳实践

时间:11-14 神话故事 提交错误

大家好,今天来为大家解答在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方法。

}

用户评论

_心抽搐到严重畸形っ°

之前遇到过这个烦恼,广播接受者执行耗时长操作卡顿真的烦!

    有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位网友表示赞同!

【在BroadcastReceiver中安全执行长时间操作的最佳实践】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活