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:协程基础
热门推荐
中国取暖产品“热”销欧洲
揭秘智能家居背后的AI黑科技
智能家居地暖改造全攻略:从操作到实现效果详解
中国取暖产品“热”销欧洲
王国荣博士谈老人胸怀与心理健康
Ella验孕棒走红,医生详解验孕最佳时机和选购要点
这些饮食习惯易导致糖尿病,需要远离
经典红烧牛肉这样做:家常川味番茄三种风味
羊蝎子:冬季餐桌上的高钙高蛋白滋补佳品
羊蝎子:冬季餐桌上的高钙高蛋白之选
深圳出发,打卡英西峰林走廊最美摄影点
吉林大学2024级研究生新生入学攻略
吉林大学南岭校区交通攻略:打卡网红景点
德乙焦点战:汉诺威96 vs 雷根斯堡,谁将笑到最后?
德乙保级大战:雷根斯堡主场迎战汉诺威96,谁能笑到最后?
德乙保级大战:雷根斯堡主场迎战汉诺威96,谁能笑到最后?
德乙保级关键战:汉诺威96客场挑战雷根斯堡,谁将占据保级主动权?
车辆型号与识别代号:汽车工业的双重编码体系
阿司匹林心血管防护效果获新证,长期服用更安全
阿司匹林用量有讲究,浙大医生提醒谨防过量
男子多服一片阿司匹林引关注,专家详解过量服用风险与应对
正确使用验孕棒:六种常见错误及应对方法
AGV小车如何提升效率?5大车型各有妙用
三七头数与品质关系:数字越小价值越高
美白精华使用指南:从成分选购到护肤流程
10款Steam上好玩的电子化桌面游戏推荐
槐树成长期有多长:从播种到成熟的全过程
辽篮的英雄、球迷宠儿,赵继伟与郭艾伦:一个无法逃避的残酷现实
以古树名木保护的意义——传承文化与维护生态的重要举措(保护古树名木)
63岁退役军人杨芳:从公园义务教唱到全国公益形象大使