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:协程基础
热门推荐
10首深情诗词,字字泣血,句句锥心,诉尽爱情的刻骨相思泪
如何有效锻炼腿部肌肉
长江三峡水利枢纽工程:世界最大水利枢纽的诞生
伴侣的缺点,是你的经验培养器
胸背疼痛是胃炎胃息肉?还是心梗前兆?两者区别很大,别再混淆了
厚植土壤!中国AI产业占全球1/10,去年融资超六千亿
房地产重磅!四大一线城市,集体实施房票政策
技术分析的三大假设、四大基本要素
怎么看内存条性能?
深度解析钢化玻璃材质,分析其特点和应用
150余位北大教授推荐最多的十本书
居民议事,让“民声”落地有声
腹主动脉瘤观察要点
杜金龙先生谈易经洗髓
城管贴的违章停车罚单不交可以吗
如何做一个产品项目经理
星座财富榜:揭秘十二星座的赚钱能力
柑橘如何喷施镁肥肥料?
有一种向往,叫云南丽江
数据正态转换的多种方法及SPSS实现
2024年广东工业大学全国录取分数线,附最低分和最低位次
瘦腹最有效的10个动作,每天15分钟见效
新建厂房储能电站配置全攻略:一文搞懂从规划到落地
千古奇文《卜算子·自嘲》全文仅 80 字,却说透了人生的无奈与自嘲
蒲公英概述
小鹅一般多久褪去绒毛
解密生姜——它到底是上火还是降火(科学解读生姜的药性和作用)
灵魂象征与意义
故意撞别人车怎么定罪
项目经理如何讨工资的