Kotlin之协程(第二趴)——使用协程控制界面

1、使用协程控制界面

通过本博客将带领你编写一个协程,用于在一定延迟之后显示消息。首先,请确保您在Android Studio中打开了start模块。

1.1、了解CoroutineScope

在Kotlin中,所有协程都在CoroutineScope中运行。作用域在其整个作业期间会控制协程的生命周期。如果取消某个作用域的作业,则该作用域内启动的所有协程也将取消。在Android上,在一些情况下,例如当用户离开ActivityFraagment时,您可以使用作用域取消所有正在运行的协程。作用域还允许您指定默认调度程序。调度程序可以控制哪个线程运行协程。

对于界面启动的额协程,通常在Dispatchers.Main(Android 上的主线程)上启动这类协程是正确的。在Dispatchers.Main上启动的协程在挂起期间不会阻塞主线程。由于ViewModel协程几乎总是在主线程上更新界面,因此在主线程上驱动协程可避免额外的线程切换。在主线程上启动的协程可在启动后随时切换调度程序。例如,它可以使用另一个调度程序从主线程外解析大型JSON结果。

复制代码
协程体统主线程安全

由于协程可以随时轻松地切换线程并将结果传递回原始线程,因此最好在主线程上启动与界面相关的协程。

使用协程时,Room和Retrofit等库原生提供主线程安全,因此您无需管理线程来进行网络或数据库调用。这往往能大幅简化代码。

但是,即使使用协程,阻塞代码(例如对列表进行排序或从文件读取数据)仍然需要显示代码来创建主线程安全。如果您使用的网络或数据库(还)不支持协程,情况也是如此。

1.2、使用viewModelScope

AndroidX lifecycle-viewmodel-ktx库将CoroutineScope添加到已配置为启动界面相关协程的ViewModel中。要使用此库,您必须将其添加到项目build.gradle(Module: start)文件中。

arduino 复制代码
dependencies {
    ...
    // replace x.x.x with latest version
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:x.x.x"
}

此库将viewModelScope添加为ViewModel类的扩展函数。此作用域绑定到Dispatchers.Main,并会在清除ViewModel后自动取消。

1.3、从线程切换到协程

MainViewModel.kt中,找到下一个TODO以及以下代码: MainViewModel.kt

kotlin 复制代码
/**
* Wait one second then update the tap count.
*/
private fun updateTaps() {
    // TODO: Convert updateTaps to use coroutines
    tapCount++
    BACKGROUND.submit {
        Thread.sleep(1_000)
        _taps.postValue("$tapCount taps")
    }
}

此代码使用BACKGROUND ExecutorService(在util/Executor.kt中定义)在后台线程中运行。由于sleep会阻塞当前线程,因此,如果在主线程上调用它,会导致界面冻结。在用户点击主视图的一秒钟后,它会请求信息提示控件。

从代码中移除BACKGROUND并重新运行代码,就能看到这种情况。加载旋转图标不会显示,并且所有内容都将在一秒钟后"跳到"最终状态。

MainViewModel.kt

kotlin 复制代码
/**
* Wait one second then update the tap count.
*/
private fun updateTaps() {
    // TODO: Convert updateTaps to use coroutines
    tapCount++
    Thread.sleep(1_000)
    _taps.postValue("$taoCount taps")
}

updateTaps替换为这个执行相同操作的基于协程的代码。您必须导入launchdelay

MainViewModel.kt

kotlin 复制代码
/**
* Wait one second then display a snackbar.
*/
fun updateTaps() {
    // launch a coroutine in viewModelScope
    viewModelScope.launch {
        tapCount++
        // suspend this coroutine for one second
        delay(1_000)
        //  resume in the main dispatcher
        // _snackbar.value can be called directly from main thread
        _taps.postValue("$tapCount taps")
    }
}

此代码执行的操作相同,即等待1秒钟后显示信息提示控件。不过,它们存在一些重要区别:

  1. viewModelScope.launch将在viewModelScope中启动协程。这意味着,当我们传递给viewModelScope的作业取消时,此作业/作用域内的所有写成都将取消。如果用户在delay返回之前离开了Activity,那么在ViewModel销毁后系统调用onCleared时,此协程将自动取消。
  2. 由于viewModelScope的默认调度程序为Dispatchers.Main,因此此协议将在主线程中启动。稍后,我们将了解如何使用不同的线程。
  3. delay属性属于suspend函数。在Android Studio的左侧边线中,此函数会以图标显示。虽然此协程在主线程上运行,但delay不会阻塞此线程1秒钟。相反,调度程序将安排协程在一秒钟内在下一句语句中回复。

开始运行测试。点击主视图后,您应该会在一秒钟后看到信息提示控件。

相关推荐
橙子1991101620 小时前
Android 第三方框架 相关
android
赏金术士21 小时前
JetPack Compose 弹窗、菜单、交互组件(五)
android·kotlin·交互·android jetpack·compose
小书房21 小时前
Kotlin的协程
kotlin·高并发·协程·异步·虚拟线程·coroutinescope
海天鹰21 小时前
高版本安卓老应用下面空白
android
猫的玖月1 天前
(七)函数
android·数据库·sql
秋91 天前
java中对操作mysql8.0.46与MySQL9.7.0有什么区别,并举例说明
android·java·adb
小书房1 天前
Kotlin协程的运行原理
android·开发语言·kotlin·协程
ooseabiscuit1 天前
Laravel10.x重磅发布:新特性全解析
android·java·开发语言·mysql
svdo1250p1 天前
“Fatal error: require(): Failed opening required...” 以及如何彻底避免它再次出现
android·ide·android studio