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:协程基础
热门推荐
《看门狗3:军团》新玩法评测:多角色控制带来全新体验
江川悦城四楼现代简约风装修指南
四楼住宅风水大揭秘:你家真的不吉利吗?
常饮速溶咖啡与衰老速度:科学解析与医生建议
甜瓜子:心血管健康的秘密武器?
对话春晚|“1、28、95” 重庆分会场舞美设计背后的关键词
创意小厨娘教你自制超香花椒油!
自制花椒油真的能护心吗?从健康功效到制作注意事项全解析
花椒油:从传统调味到健康饮食新选择
川菜大厨教你用花椒油做麻婆豆腐
《看门狗》:在芝加哥当个顶级黑客有多酷?
“双减”背景下教师心理健康问题与应对策略
家校共育:如何打造和谐师生关系?
提升社交技巧:建立自信与有效沟通的实用指南
一位太极拳师的“拳健天下”二十载
西南大学研究:太极拳锻炼可通过改善睡眠提升老年人记忆功能
春节将至,如何用新年祝福拉近你和老板的距离?
老板的新年祝福,你准备好了吗?
这4种瓜可以缓解便秘,但如果有苦味要立即扔掉
过年囤货必看:如何挑到放心原味瓜子?
正确吃瓜子,远离糖尿病隐患
感恩节到了!给舞蹈老师的暖心话
五台山冬季游,跟团还是自由行?
五台山徒步路线全攻略:一场身心的修行之旅
火命的人性格命运特征
命理分析:水命和火命真的相克吗?
SCREENX版《封神第二部》引爆春节档
《封神第二部》定档大年初一,主创团队揭秘
电瓶车充电桩安全保障措施,如何确保用户安全?
《熊出没之环球大冒险》:一部动画的诞生与成长