在Repository和ViewModel之间共享同一个MutableLiveData。

9
我正在努力理解Architecture Components / MVVM。
假设我有一个存储库(repository)、一个 ViewModel 和一个 Fragment。我正在使用一个名为 Resource 的类作为包装器来暴露网络状态,就像《指南》中建议的那样。
我的存储库当前看起来大致如下(简化了一些以节省篇幅):
class MyRepository {

  fun getLists(organizationId: String) {
    var data = MutableLiveData<Resource<List<Something>>>()
    data.value = Resource.loading()

    ApolloClient().query(query)
        .enqueue(object : ApolloCall.Callback<Data>() {
            override fun onResponse(response: Response<Data>) {
                response.data()?.let {
                    data.postValue(Resource.success(it))
                }
            }

            override fun onFailure(exception: ApolloException) {
                data.postValue(Resource.exception(exception))
            }
        })
}

然后在ViewModel中,我也声明了一个MutableLiveData:
var myLiveData = MutableLiveData<Resource<List<Something>>>()

fun getLists(organizationId: String, forceRefresh: Boolean = false) {
   myLiveData = myRepository.getLists(organizationId)
}

最后,片段:

viewModel.getLists.observe(this, Observer {
        it?.let {
            if (it.status.isLoading()) showLoading() else hideLoading()

            if (it.status == Status.SUCCESS) {
                it.data?.let {
                    adapter.replaceData(it)
                    setupViews()
                }
            }

            if (it.status == Status.ERROR) {
                // Show error
            }
        }
    })

如您所见,观察者可能会出现问题,因为在此过程中LiveData变量将被重置(Repository会创建一个新实例)。
我正在尝试找出确保Repository和ViewModel之间使用相同LiveData变量的最佳方法。
我考虑将LiveData从ViewModel传递到getLists方法中,以便Repository使用来自ViewModel的对象,但即使它可以工作,这样做似乎是错误的。
我的意思是像这样:
ViewModel
var myLiveData = MutableLiveData<Resource<List<Something>>>()

fun getLists(organizationId: String, forceRefresh: Boolean = false) {
   myRepository.getLists(myLiveData, organizationId)
}

仓库

fun getLists(data: MutableLiveData<Resource<List<Something>>>, organizationId: String) {
    ...
}

1
你可能正在寻找 https://developer.android.com/reference/android/arch/lifecycle/Transformations.html#switchmap 在你的 VM 中。 - NSimon
为什么不在您的存储库中创建实时数据,然后将其传递到视图层? - AutonomousApps
1个回答

7

感谢@NSimon的提示,我想我已经弄清楚如何做了。

我的代码库没有改变,我的ViewModel代码看起来像这样:

class MyViewModel : ViewModel() {
  private val myRepository = MyRepository()

  private val organizationIdLiveData = MutableLiveData<String>()
  private val lists = Transformations.switchMap(organizationIdLiveData) { organizationId -> myRepository.getLists(organizationId) }

  fun getLists() : LiveData<Resource<MutableList<Something>>> {
    return lists
  }

  fun fetchLists(organizationId: String, forceRefresh: Boolean = false) {
    if (organizationIdLiveData.value == null || forceRefresh) {
      organizationIdLiveData.value = organizationId
    }
  }
}

我在我的片段中观察了getLists(),当我想要数据时调用viewModel.fetchLists(id)。看起来合理吗?


1
这似乎是一个不错的答案,但是你如何解决延迟初始化的LiveData对象的问题呢?例如:一旦你获取了列表,你想获取另一种数据。如果没有一种观察它在视图中的方法,你怎么能做到这一点呢? - Rishabh Jain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接