Kotlin:runBlocking导致App应用出现ANR问题实例
创作时间:
作者:
@小白创作中心
Kotlin:runBlocking导致App应用出现ANR问题实例
引用
CSDN
1.
https://blog.csdn.net/ChinaDragon10/article/details/136736445
本文通过一个具体实例,详细解释了Kotlin中runBlocking导致Android应用出现ANR(Application Not Responding)问题的原因,并提供了使用GlobalScope.launch作为解决方案。
runBlocking简介
runBlocking 是常规函数;
runBlocking 方法会阻塞当前线程来等待;
runBlocking 的主线程会一直 阻塞 直到 runBlocking 内部的协程执行完毕。
runBlocking导致App应用出现ANR问题实例的效果
点击页面上的刷新按钮调用 refreshByrunBlocking方法,此方法里模拟了等待30秒耗时操作,当点击刷新按钮等待3秒左右,点击详情按钮,页面出现ANR弹框如下图所示
页面布局activity_test_anr_by_runblocking.xml代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_refresh"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="60dp"
android:layout_marginRight="20dp"
android:gravity="center"
android:onClick="onClick"
android:text="刷新"
android:textColor="@color/black"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_detail"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginTop="60dp"
android:gravity="center"
android:onClick="onClick"
android:text="详情"
android:textColor="@color/black"
android:textSize="20sp"
app:layout_constraintLeft_toLeftOf="@+id/btn_refresh"
app:layout_constraintRight_toRightOf="@+id/btn_refresh"
app:layout_constraintTop_toBottomOf="@+id/btn_refresh" />
<TextView
android:id="@+id/tv_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:onClick="onClick"
android:textColor="@color/black"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="@+id/btn_detail"
app:layout_constraintRight_toRightOf="@+id/btn_detail"
app:layout_constraintTop_toBottomOf="@+id/btn_detail"
tools:text="用户信息" />
</androidx.constraintlayout.widget.ConstraintLayout>
实体类:PsersonBean.kt代码
data class PsersonBean(val name: String, var moblie: String? = null)//至少有一个构造函数
TestANRByRunBlockingActivity.kt代码
package example.demo.kotlin.activity
import android.app.Activity
import android.os.Bundle
import android.view.View
import android.widget.TextView
import example.demo.kotlin.R
import example.demo.kotlin.bean.PsersonBean
import example.demo.kotlin.utils.LogUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
class TestANRByRunBlockingActivity : Activity() {
private lateinit var tv_detail: TextView
private var psersonBean: PsersonBean
init {
psersonBean = PsersonBean("测试用户01")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_anr_by_runblocking)
initView()
}
override fun onStart() {
super.onStart()
showData()
}
fun initView() {
tv_detail = findViewById(R.id.tv_detail)
}
fun showData() {
//使用lateinit var 延时初始化,这里安全起见,判断是否 isInitialized
if (::tv_detail.isInitialized) {
tv_detail.setText("$psersonBean")//注意,因为PsersonBean是 data class 类型 不需要重新toString 函数
}
}
fun onClick(view: View) {
when (view.id) {
R.id.btn_refresh -> refreshByrunBlocking2()
R.id.btn_detail -> detail()
}
}
/**
* 出现了ANR问题
*/
fun refreshByrunBlocking() {
runBlocking(context = Dispatchers.IO) {
LogUtil.i("开始执行 刷新 耗时操作了")
delay(30000)//假设30秒,可以假设真实网络请求出现超时了,方便演示出现ANR问题
psersonBean = PsersonBean("测试用户02")
LogUtil.i("刷新 耗时操作结束")
}
LogUtil.i("刷新 耗时操作 事件执行完毕")
showData()
}
/**
* runBlocking里即使使用 async 也会出现ANR问题
*/
fun refreshByrunBlocking2() {
runBlocking(context = Dispatchers.IO) {
LogUtil.i("开始执行 刷新 耗时操作了")
val psersonBean = async {
delay(30000)//假设30秒,可以假设真实网络请求出现超时了,方便演示出现ANR问题
PsersonBean("测试用户02")
}
LogUtil.i("刷新 耗时操作结束")
}
LogUtil.i("刷新 耗时操作 事件执行完毕")
showData()
}
/**
* 使用GlobalScope.launch ,没有出现ANR问题
*/
fun refreshByGlobalScopeLaunch() {
GlobalScope.launch(context = Dispatchers.IO) {
LogUtil.i("开始执行 刷新 耗时操作了")
delay(30000)//假设30秒,可以假设真实网络请求出现超时了,方便演示出现ANR问题
psersonBean = PsersonBean("测试用户02")
LogUtil.i("刷新 耗时操作结束")
withContext(Dispatchers.Main){//切换到主线程更新UI
showData()
}
}
LogUtil.i("调用了 refreshByGlobalScopeLaunch 方法,没有阻塞当前线程")
}
fun detail() {
LogUtil.i("执行了查看详情事件")
psersonBean.moblie = "12345678901"
showData()
}
}
使用GlobalScope.launch解决ANR问题
点击页面上的刷新按钮调用 refreshByGlobalScopeLaunch方法,此方法里模拟了等待30秒耗时操作,当点击刷新按钮等待3秒左右,点击详情按钮,页面数据正常显示如下图所示
刷新耗时操作结束,主线程更新UI
总结
- runBlocking主线程会一直 阻塞 直到 runBlocking内部的协程执行完毕,执行长时间耗时操作会导致App应用出现ANR问题。
- runBlocking里即使使用async也会导致App应用出现ANR问题。
- GlobalScope.launch可以解决耗时操作App应用出现ANR问题,注意需要配合withContext(Dispatchers.Main)进行更新UI操作
推荐
Kotlin:协程基础
热门推荐
肌酸应该运动前还是运动后喝
人像摄影常用景别详解
【CP AUTOSAR】Adc(ADCDriver)分析和使用
SDG中心发布可持续发展科学卫星1号系列图集
特朗普关税生效后欧美股债齐跌!亚太股市今日反弹,中国资产继续被看好
为什么半导体产业链对国家安全至关重要?
培养青少年元认知能力的八大策略
蒙特卡洛方法(Monte Carlo method)/统计模拟方法
消防救援队伍的培训和演练如何进行?
秃鹫加入滑翔伞爱好者的行列,带领他们穿越西班牙山脉(称为滑翔伞运动)
IT运维服务的响应时间一般是多久?
气瓶内部气体压力标准及安全使用规范
10大关键技术解构:智能合同审查系统全景解析
煅瓦楞子的功效与作用及药用价值
如何查岗位需求信息管理
玻尿酸打溶解酶后多久能溶掉?作用原理&成效/溶解时间/维护建议一览
地道重庆人在家吃火锅会买哪些菜?这份清单请收藏
我国安全围挡法定高度及要求
玉米的性味归经是什么
中国科学家研发国际首款大面阵CMOS太赫兹波图像传感器
德里克·罗斯:从MVP巅峰到谷底重生,炸裂球风燃爆NBA!
甘味药:中医保健的秘密武器
如何治疗孩子的分离焦虑
离子电极法测定水中氟化物含量(离子电极法测定水中氟化物浓度的方法)
文旅设备更新升级 索道及电梯成投资重点
金昌:贴心服务+民生项目,为残疾人开启幸福加速键
樊振东的乒乓之路
脑梗吃了药后头疼怎么办
直系亲属间房屋过户,赠与、买卖方式的税费有何区别?
《中国妇女》微调查:当代女性择偶观新变化