简体   繁体   English

如何将 ViewModelScope 等异步协程 scope 的值返回到您的 UI?

[英]How to return value from async coroutine scope such as ViewModelScope to your UI?

I'm trying to retrieve a single entry from the Database and successfully getting the value back in my View Model with the help of viewModelScope, but I want this value to be returned back to the calling function which resides in the fragment so it can be displayed on a TextView.我正在尝试从数据库中检索单个条目,并在 viewModelScope 的帮助下成功地将值返回到我的视图 Model 中,但我希望将此值返回给驻留在片段中的调用 function显示在 TextView 上。 I tried to return the value the conventional way but it didn't work.我试图以传统方式返回值,但它不起作用。 So, How Can I return this value from viewModelScope.launch to the calling function?那么,如何将 viewModelScope.launch 中的这个值返回给调用 function?

View Model查看 Model

    fun findbyID(id: Int) {
    viewModelScope.launch {
       val returnedrepo = repo.delete(id)
        Log.e(TAG,returnedrepo.toString())
        // how to return value from here to Fragment
    }

}

Repository存储库

    suspend fun findbyID(id : Int):userentity{
    val returneddao = Dao.findbyID(id)
    Log.e(TAG,returneddao.toString())
    return returneddao
}

LiveData can be used to get value from ViewModel to Fragment . LiveData可用于从ViewModel获取值到Fragment

Make the function findbyID return LiveData and observe it in the fragment.使函数findbyID返回LiveData并在片段中观察它。

Function in ViewModel ViewModel函数

fun findbyID(id: Int): LiveData</*your data type*/> {
    val result = MutableLiveData</*your data type*/>()
    viewModelScope.launch {
       val returnedrepo = repo.delete(id)
       result.postValue(returnedrepo)
    }
    return result.
}

Observer in Fragment Fragment观察者

findbyId.observer(viewLifeCycleOwner, Observer { returnedrepo ->
   /* logic to set the textview */
})

Thank you Nataraj KR for your Help!感谢 Nataraj KR 的帮助!

Following is the code that worked for me.以下是对我有用的代码。

View Model查看模型

class ViewModel(application: Application):AndroidViewModel(application) {
val TAG = "ViewModel"
val repo: theRepository
val alldata:LiveData<List<userentity>>
val returnedVal = MutableLiveData<userentity>()
init {
    val getDao = UserRoomDatabase.getDatabase(application).userDao()
    repo = theRepository(getDao)
    alldata = repo.allUsers

}

fun findbyID(id: Int){
    viewModelScope.launch {
       returnedVal.value = repo.findbyID(id)
    }
}

} }

Fragment分段

 override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    val usermodel = ViewModelProvider(this).get(ViewModel::class.java)
    usermodel.alldata.observe(this, Observer {
        Log.e(TAG,usermodel.alldata.value.toString())
    })
    usermodel.returnedVal.observe(this, Observer {
        tv1.text = usermodel.returnedVal.value.toString()
    })

    allData.setOnClickListener {
        tv1.text = usermodel.alldata.value.toString()
    }

    findByID.setOnClickListener {
        usermodel.findbyID(et2.text.toString().toInt())
    }
}

Another way without using LiveData would be like this,另一种不使用 LiveData 的方法是这样的,

Similar to viewModelScope there is also a lifecycleScope available with lifecycle-aware components, which can be used from the UI layer.viewModelScope类似,还有一个可以用于lifecycleScope周期感知组件的生命周期范围,可以从 UI 层使用。 Following is the example,以下是示例,

Fragment分段

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    findByID.setOnClickListener {
        lifecycleScope.launch{
            val res = usermodel.findbyID(et2.text.toString().toInt())
            // use returned value to do anything.
        }
    }
}

ViewModel视图模型

//1st option
// make the function suspendable itself.use aync instead of launch and then
// use await to collect the returned value.
suspend fun findbyID(id: Int): userEntity  {
    val job = viewModelScope.async {
       val returnedrepo = repo.delete(id)
       Log.e(TAG,returnedrepo.toString())
       return@async returnedrepo
    }
    return job.await()
}

//2nd option
// make the function suspendable itself. but switch the execution on IO
// thread.(since you are making a DB call)
suspend fun findbyID(id: Int): userEntity  {
    return withContext(Dispatchers.IO){
       val returnedrepo = repo.delete(id)
       Log.e(TAG,returnedrepo.toString())
       return@withContext returnedrepo
    }
}

Since LiveData is specific to Android Environment, Using Kotlin Flow becomes a better option in some places, which offers similar functionality.由于 LiveData 特定于 Android 环境,因此在某些地方使用 Kotlin Flow 成为更好的选择,它提供了类似的功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM