简体   繁体   English

Android ViewModel协程模式

[英]Android viewmodel coroutine pattern

I would like to hear some critics on the way I have implemeneted viewmodel data fetching using coroutine. 我想听听一些批评者对我使用协程实现视图模型数据获取的方式的评论。 My goal is clean way to write ViewModels. 我的目标是编写ViewModels的干净方法。 But isn't it too big of overhead? 但这不是太大的开销吗? I haven't found so far some clean solution. 到目前为止,我还没有找到一些干净的解决方案。 Let me know your tips. 让我知道你的提示。 I wanted to avoid to write if (!::users.isInitialized) as it is in the official tutorial . 我想避免像在正式教程中那样编写if (!::users.isInitialized)

class LiveDataLoader <T>{
    val liveData = MutableLiveData<T>()
    var loaded:Boolean = false
}

abstract class CustomViewModel : ViewModel(){
    private val viewModelJob = Job()
    private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

    fun <T> get(container: LiveDataLoader<T>, loader: ()->T): LiveData<T>{
        if (!container.loaded){
            container.loaded = true
            uiScope.launch{
                container.liveData.postValue(loader.invoke())
            }
        }
        return container.liveData;
    }

    override fun onCleared() {
        super.onCleared()
        viewModelJob.cancel()
    }
}

class ActivityTodoGroupsViewModel() : CustomViewModel(){
    private val groups = LiveDataLoader<MutableList<TaskGroupWithTasks>>()
    private val tasks = LiveDataLoader<MutableList<TodoTask>>()

    private lateinit var tasksx: MutableLiveData<MutableList<TodoTask>>

    fun getTaskGroups() = get(groups){
        AppDatabase.db.toDoTasksDAO.getGroupsWithItems()
    }

    fun getUpcomingTasks() = get(tasks){
        val calendar = Calendar.getInstance()
        calendar.add(Calendar.DAY_OF_YEAR, -7)
        AppDatabase.db.toDoTasksDAO.getRecentTasks(calendar)
    }

}

In general it's always good to not expose the Mutable* types too much. 通常,最好不要公开太多Mutable*类型。 This ensures data consistency. 这样可以确保数据的一致性。 Also it seems like you're trying a achieve something similar to lazy , so why not use it. 而且似乎您正在尝试实现类似于lazy的成就,所以为什么不使用它。

So you could consider an extension function to CoroutineScope to convert a suspending function to a simple LiveData : 因此,您可以考虑将CoroutineScope的扩展功能转换为将暂停功能转换为简单的LiveData

fun <V> CoroutineScope.liveData(
        provider: suspend () -> V
) = lazy<LiveData<V>> {
    MutableLiveData<V>().apply {
        launch {
            postValue(provider())
        }
    }
}

If you also have your ViewModel implement CoroutineScope , you could use it as: 如果您还拥有ViewModel实现CoroutineScope ,则可以将其用作:

val taskGroups() by liveData {
    AppDatabase.db.toDoTasksDAO.getGroupsWithItems()
}

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

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