Android ViewModel协程模式

时间:2019-02-04 22:22:20

标签: android kotlin coroutine

我想听听一些批评者对我使用协程实现视图模型数据获取的方式的评论。我的目标是编写ViewModels的干净方法。但这不是太大的开销吗?到目前为止,我还没有找到一些干净的解决方案。让我知道你的提示。我想避免像在官方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)
    }

}

1 个答案:

答案 0 :(得分:1)

通常,最好不要公开过多的Mutable*类型。这样可以确保数据的一致性。而且似乎您正在尝试实现类似于lazy的功能,所以为什么不使用它。

因此,您可以考虑使用扩展功能CoroutineScope来将悬浮函数转换到简单的LiveData

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

如果您也有自己的ViewModel工具CoroutineScope,则可以将其用作:

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