android - 如何从协程后台线程更新UI线程?

标签 android kotlin kotlin-coroutines

我有一个函数displayDirectoryContents2(file: File),它扫描所有文件并检查文件和目录。我想要的是在 UI 线程的 TextView 中显示当前文件路径

lateinit var textView: TextView


GlobalScope.launch(Dispatchers.IO) {
 displayDirectoryContents2(file)
}

函数代码

private fun displayDirectoryContents2(dir: File?){
    try {
        val files = dir?.listFiles()!!

        files.forEach {

            if (it.isDirectory) {
                displayDirectoryContents2(it)
            } else { 
                   if (it.isFile) {
                    textView.text = it.name // to Update the file name in UI thread
              }
        }


    } catch (e: IOException) {
        e.printStackTrace()
    }
}

我是 Kotlin 协程的新手。实际上我想在后台线程中运行函数 displayDirectoryContents2(file: File) 并更新该函数在 UI 线程中读取的文件名,就像 AsyncTask 一样。

最佳答案

您可以切换调度程序上下文(Dispatchers.IO 用于逻辑,然后切换到 Dispatchers.Main 用于更新 UI),或者您可以将代码移至 ViewModel 中,并使用相同的上下文切换技术或使用 postvalue()实时数据。下面是执行后者的示例。您可以在此处阅读 ViewModel:https://developer.android.com/topic/libraries/architecture/viewmodel

import androidx.lifecycle.LiveData 
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class MyViewModel() : ViewModel() {
    private val files: MutableLiveData<List<String>> by lazy {
        MutableLiveData<List<String>>()
    }
    fun loadFiles(path: String) {
        viewModelScope.launch(){
            doLoadFiles()
        }
    }
    private suspend fun doLoadFiles() {
        withContext(Dispatchers.IO) {
            val results = listOf("patha", "pathb")//replace with your actual code
            files.postValue(results)
        }
    }
    fun getFiles(): LiveData<List<String>> = files
}

然后从您的 Activity 中这样调用它

import androidx.appcompat.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders

import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val model = ViewModelProviders.of(this)[MyViewModel::class.java]
        model.getFiles().observe(this, Observer<List<String>>{ paths ->
            // update UI
            println (paths)
        })
        model.loadFiles("S")

    }

在您的 build.gradle 文件中,确保导入相关依赖项

 def lifecycle_ver = "2.2.0-rc02"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_ver"
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_ver"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_ver"

关于android - 如何从协程后台线程更新UI线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59555307/

相关文章:

kotlin-coroutines - Kotest 与 kotlinx-coroutines-test 集成

java - 如何获取 Canvas 的当前位图?

java - 来自不同类的自定义 SeekBarPreference setProgress?

android - 如何在 map fragment API v2 布局顶部添加按钮

java.util.HashMap 无法转换为 java.util.ArrayList

android - 如何在 android kotlin 中使用 Socket.IO

android - 在android中创建另一个字符串xml值文件

Android Room.databaseBuilder().createFromFile() 静默失败

multithreading - Kotlin 协程 : Waiting for multiple threads to finish

android - 在 Task<T> 完成之前暂停协程的正确方法