web-dev-qa-db-ja.com

コルーチンのバックグラウンドスレッドからUIスレッドを更新する方法は?

すべてのファイルをスキャンしてファイルとディレクトリをチェックする関数displayDirectoryContents2(file:File)があります。私が欲しいのは、UIスレッドのテキストビューに現在のファイルパスを表示することです

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)を実行し、AsyncTaskと同じように、関数がUIスレッドで読み取っているファイルの名前を更新したいと思います。

4
MAD LAD

ディスパッチャーコンテキスト(ロジックの場合はDispatchers.IO、UIの更新の場合はDispatchers.Main)を切り替えるか、コードをViewModelに移動して、同じコンテキスト切り替え手法を使用するか、LiveDataの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
}

それからあなたの活動からこのように呼んでください

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"
1
Dmitri