2

我想对不同来源使用相同的 LiveData。一个来自 API 调用,它是可观察的,另一个来自数据库,它是 LiveData。我希望能够做这样的事情:

private LiveData<List<Items>> items = new MutableLiveData<>();

// this one comes from an API and it's an observable
public void onApiItemsSelected(String name) {
 Disposable disposable = repository.getItemsFromApi(name)
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(itemsList -> {
     items.setValue(itemsList);
 });

 compositeDisposable.add(disposable);
}

// this one comes from the database and it's a livedata that I want to transform first
public void onDatabaseItemsSelected() {
 items = Transformations.map(repository.getItemsFromdatabase(), itemsList -> {
    List<Items> finalItemsList = new ArrayList<>();

    for (Item item : itemsList) {
      finalItemsList.add(itemsList.toSomething());
    }

    return finalItemsList;
 });
}

问题是 Transformation.map 总是返回一个 LiveData 并且为了使items.setValue(itemsList)项目需要是一个 MutableLiveData。我尝试使用 MediatorLiveData,但它调用了两个源并混合了所有内容。这不是我在这里需要的。我需要一个来源或另一个。可能吗?

4

2 回答 2

1

我认为您可以将此责任委托给您的存储库。

例如,请参阅此开源项目和相关文章,了解更多信息。

基本上,存储库处理决定从哪个源获取数据的所有复杂性(请参阅JobRepository)。它将一个 rx 暴露ObservableViewModel(参见JobsViewModel)。然后 ViewModel 所要做的就是更新LiveData

private val presentation: MutableLiveData<Presentation> = MutableLiveData()

fun bind() {
        jobRepository.getJobs(true)
            .subscribeOn(Schedulers.io())
            .subscribe { resource: Resource<List<JobWithRelations>> ->
                when (resource) {
                    // commenting some parts for brevity ...
                    is Resource.ResourceFound -> {
                        presentation.postValue(Presentation(getApplication(), resource.data!!))
                    }
                    // ...
                }
            }.addTo(compositeDisposable)
    }

管理多个数据源很复杂。在构建此架构所涉及的许多方面中,要记住的事情包括:

  • 内存缓存过期策略
  • 数据库缓存的策略,例如,当用户离线时
  • API 调用的限制和重试
  • 当新数据来自网络时更新内存缓存或数据库的策略

一个可以帮助您的库是 Dropbox Store。有了它,您可以从他们的文档中构建您的数据源,如下例所示:

StoreBuilder
    .from(
        fetcher = nonFlowValueFetcher { api.fetchSubreddit(it, "10").data.children.map(::toPosts) },
        sourceOfTruth = SourceOfTrue.from(
            reader = db.postDao()::loadPosts,
            writer = db.postDao()::insertPosts,
            delete = db.postDao()::clearFeed,
            deleteAll = db.postDao()::clearAllFeeds
        )
    ).build()

然后获取 ViewModel 中的数据:

private val presentation: MutableLiveData<Presentation> = MutableLiveData()

lifecycleScope.launchWhenStarted {
  store.stream(StoreRequest.cached(key = key, refresh=true)).collect { response ->
    when(response) {
        // commenting some parts for brevity ...
        is StoreResponse.Data -> {
            presentation.postValue(response.value)
        }
        // ...
    }
  }
}
于 2020-05-14T20:53:31.740 回答
0

我不确定这是最佳做法,但我认为可以解决问题。


public void onDatabaseItemsSelected() {
items.value = repository.getItemsFromdatabase().value;
};

语法可能不准确,因为我对 java 知之甚少,我主要做 kotlin。但问题是:当用户单击 Api 时,让您的 onApiItemsSelected() 运行,这将设置items的值,当用户单击数据库时,使onDatabaseItemsSelected()运行,因此它将替换存储库结果的items值。 getItemsFromDatabase()

于 2020-05-14T20:19:03.860 回答