如何观察 PagedList 数据?
How to observe PagedList data?
我正在使用 Paging Library 和 Android 架构组件。我只是想观察 pagedlist 实时数据并在有变化时更新我的 RecyclerView。
我正在观察 isLoadingLiveData、isEmptyLiveData 和 errorLiveData 对象,它们是在我的 ViewModel 中创建并在我的片段中观察到的 MediatorLiveData 对象。并且还观察 resultLiveData returns 从远程获取的 Gist 列表。
在我的 ViewModel 中,我创建了一个 PagedList LiveData,只要它的数据发生变化,我就想更新 isLoadingLiveData、isEmptyLiveData、errorLiveData 和 PagedListAdapter。因此,我将 isLoadingLiveData、isEmptyLiveData、errorLiveData 和 resultLiveData 定义为 MediatorLiveData 对象。我添加了 resultLiveData 作为这些对象的来源。因此,当 resultLiveData 发生变化时,将调用这些对象的 onChanged 方法。而 resultLiveData 依赖于 userNameLiveData,所以当 userNameLiveData 发生变化时,将调用 allGistsLiveData 并获取数据。例如,当用户滑动列表时,我正在设置 userNameLiveData 并再次进行网络调用。
我的视图模型:
private val userNameLiveData = MutableLiveData<String>()
private var gists: LiveData<PagedList<Gist>>? = null
val allGistsLiveData: LiveData<PagedList<Gist>>
get() {
if (null == gists) {
gists = GistModel(NetManager(getApplication()), getApplication()).getYourGists(userNameLiveData.value!!).create(0,
PagedList.Config.Builder()
.setPageSize(PAGED_LIST_PAGE_SIZE)
.setInitialLoadSizeHint(PAGED_LIST_PAGE_SIZE)
.setEnablePlaceholders(PAGED_LIST_ENABLE_PLACEHOLDERS)
.build())
}
return gists!!
}
val resultLiveData = MediatorLiveData<LiveData<PagedList<Gist>>>().apply {
this.addSource(userNameLiveData) {
gists = null
this.value = allGistsLiveData
}
}
val isLoadingLiveData = MediatorLiveData<Boolean>().apply {
this.addSource(resultLiveData) { this.value = false }
}
val isEmptyLiveData = MediatorLiveData<Boolean>().apply {
this.addSource(resultLiveData) { this.value = false }
}
val errorLiveData = MediatorLiveData<Boolean>().apply {
this.addSource(resultLiveData) {
if (it == null) {
this.value = true
}
}
}
fun setUserName(userName: String) {
userNameLiveData.value = userName
}
和我的片段:
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.isEmptyLiveData.observe(this@YourGistsFragment, Observer<Boolean> { isVisible ->
emptyView.visibility = if (isVisible!!) View.VISIBLE else View.GONE
})
viewModel.isLoadingLiveData.observe(this@YourGistsFragment, Observer<Boolean> {
it?.let {
swipeRefreshLayout.isRefreshing = it
}
})
viewModel.errorLiveData.observe(this@YourGistsFragment, Observer<Boolean> {
it?.let {
showSnackBar(context.getString(R.string.unknown_error))
}
})
viewModel.setUserName("melomg")
viewModel.resultLiveData.observe(this@YourGistsFragment, Observer { it -> gistAdapter.setList(it?.value) })
}
override fun onRefresh() {
viewModel.setUserName("melomg")
}
我的存储库:
fun getYourGists(userName: String): LivePagedListProvider<Int, Gist> {
return remoteDataSource.getYourGists(userName, GitHubApi.getGitHubService(context))
}
我的远程数据源:
fun getYourGists(username: String, dataProvider: GitHubService): LivePagedListProvider<Int, Gist> {
return object : LivePagedListProvider<Int, Gist>() {
override fun createDataSource(): GistTiledRemoteDataSource<Gist> = object : GistTiledRemoteDataSource<Gist>(username, dataProvider) {
override fun convertToItems(items: ArrayList<Gist>?): ArrayList<Gist>? {
return items
}
}
}
}
我试图从 this project 创建这个解决方案。但我的问题是
resultLiveData 在不等待网络调用响应的情况下一直在变化,因此响应的结果被忽略并且我的 ui 在数据到达之前被更新。由于 resultLiveData 在请求之前发生变化,因此还没有数据。简单地说,我如何观察分页列表的实时数据?
最后,我找到了一个可行的解决方案,但我认为这不是最佳解决方案。因此,如果您有任何想法,请不要犹豫回答。这是我的解决方案:
我放弃了包装 PagedList data with MediatorLiveData。我仍然将所有其他实时数据 (isLoadingLiveData, isEmptyLiveData, errorLiveData
) 保留为 MediatorLiveData
,但在我的要点 PagedList LiveData 初始化时添加了它们的源。这是代码:
private var gists: LiveData<PagedList<Gist>>? = null
private val userNameLiveData = MutableLiveData<String>()
val isLoadingLiveData = MediatorLiveData<Boolean>()
val isEmptyLiveData = MediatorLiveData<Boolean>()
val errorLiveData = MediatorLiveData<ErrorMessage>()
val allGistsLiveData: LiveData<PagedList<Gist>>
get() {
if (gists == null) {
gists = GistModel(NetManager(getApplication()), getApplication()).getYourGists(userNameLiveData.value!!).create(0,
PagedList.Config.Builder()
.setPageSize(Constants.PAGED_LIST_PAGE_SIZE)
.setInitialLoadSizeHint(Constants.PAGED_LIST_PAGE_SIZE)
.setEnablePlaceholders(Constants.PAGED_LIST_ENABLE_PLACEHOLDERS)
.build())
isLoadingLiveData.addSource(gists) { isLoadingLiveData.value = false }
isEmptyLiveData.addSource(gists) {
if (it?.size == 0) {
isEmptyLiveData.value = true
}
}
errorLiveData.addSource(gists) {
if (it == null) {
errorLiveData.value = ErrorMessage(errorCode = ErrorCode.GENERAL_ERROR)
}
}
}
}
return gists!!
}
fun setUserName(userName: String) {
isLoadingLiveData.value = true
userNameLiveData.value = userName
gists = null
allGistsLiveData
}
有更好的方法来做到这一点。看这个例子:
https://github.com/android/architecture-components-samples/tree/master/PagingWithNetworkSample
诀窍是在您的数据源中放入一个可变的实时数据,如下所示:
enum class NetworkState { LOADING, LOADED, FAILURE }
val networkState = MutableLiveData<NetworkState>()
override fun loadInitial(params: LoadInitialParams<String>, callback: LoadInitialCallback<String, OrderService.Resource>) {
networkState.post(NetworkState.LOADING)
ApiClient.listMyObjects(
onSuccess = { list ->
networkState.post(NetworkState.LOADED)
callback.onResult(list)
}
onFailure = {
networkState.post(NetworkState.FAILURE)
}
)
}
然后您可以通过以下方式收听您的分页列表和网络状态:
val myDataSource = MyDataSource.Factory().create()
myDataSource.toLiveData().observe(viewLifeCycle, Observer { pagedList ->
// Update your recycler view
myRecyclerViewAdapter.submitList(pagedList)
})
myDataSource.networkState.observe(viewLifeCycle, Observer { state ->
// Show errors, retry button, progress view etc. according to state
})
我正在使用 Paging Library 和 Android 架构组件。我只是想观察 pagedlist 实时数据并在有变化时更新我的 RecyclerView。
我正在观察 isLoadingLiveData、isEmptyLiveData 和 errorLiveData 对象,它们是在我的 ViewModel 中创建并在我的片段中观察到的 MediatorLiveData 对象。并且还观察 resultLiveData returns 从远程获取的 Gist 列表。
在我的 ViewModel 中,我创建了一个 PagedList LiveData,只要它的数据发生变化,我就想更新 isLoadingLiveData、isEmptyLiveData、errorLiveData 和 PagedListAdapter。因此,我将 isLoadingLiveData、isEmptyLiveData、errorLiveData 和 resultLiveData 定义为 MediatorLiveData 对象。我添加了 resultLiveData 作为这些对象的来源。因此,当 resultLiveData 发生变化时,将调用这些对象的 onChanged 方法。而 resultLiveData 依赖于 userNameLiveData,所以当 userNameLiveData 发生变化时,将调用 allGistsLiveData 并获取数据。例如,当用户滑动列表时,我正在设置 userNameLiveData 并再次进行网络调用。
我的视图模型:
private val userNameLiveData = MutableLiveData<String>()
private var gists: LiveData<PagedList<Gist>>? = null
val allGistsLiveData: LiveData<PagedList<Gist>>
get() {
if (null == gists) {
gists = GistModel(NetManager(getApplication()), getApplication()).getYourGists(userNameLiveData.value!!).create(0,
PagedList.Config.Builder()
.setPageSize(PAGED_LIST_PAGE_SIZE)
.setInitialLoadSizeHint(PAGED_LIST_PAGE_SIZE)
.setEnablePlaceholders(PAGED_LIST_ENABLE_PLACEHOLDERS)
.build())
}
return gists!!
}
val resultLiveData = MediatorLiveData<LiveData<PagedList<Gist>>>().apply {
this.addSource(userNameLiveData) {
gists = null
this.value = allGistsLiveData
}
}
val isLoadingLiveData = MediatorLiveData<Boolean>().apply {
this.addSource(resultLiveData) { this.value = false }
}
val isEmptyLiveData = MediatorLiveData<Boolean>().apply {
this.addSource(resultLiveData) { this.value = false }
}
val errorLiveData = MediatorLiveData<Boolean>().apply {
this.addSource(resultLiveData) {
if (it == null) {
this.value = true
}
}
}
fun setUserName(userName: String) {
userNameLiveData.value = userName
}
和我的片段:
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.isEmptyLiveData.observe(this@YourGistsFragment, Observer<Boolean> { isVisible ->
emptyView.visibility = if (isVisible!!) View.VISIBLE else View.GONE
})
viewModel.isLoadingLiveData.observe(this@YourGistsFragment, Observer<Boolean> {
it?.let {
swipeRefreshLayout.isRefreshing = it
}
})
viewModel.errorLiveData.observe(this@YourGistsFragment, Observer<Boolean> {
it?.let {
showSnackBar(context.getString(R.string.unknown_error))
}
})
viewModel.setUserName("melomg")
viewModel.resultLiveData.observe(this@YourGistsFragment, Observer { it -> gistAdapter.setList(it?.value) })
}
override fun onRefresh() {
viewModel.setUserName("melomg")
}
我的存储库:
fun getYourGists(userName: String): LivePagedListProvider<Int, Gist> {
return remoteDataSource.getYourGists(userName, GitHubApi.getGitHubService(context))
}
我的远程数据源:
fun getYourGists(username: String, dataProvider: GitHubService): LivePagedListProvider<Int, Gist> {
return object : LivePagedListProvider<Int, Gist>() {
override fun createDataSource(): GistTiledRemoteDataSource<Gist> = object : GistTiledRemoteDataSource<Gist>(username, dataProvider) {
override fun convertToItems(items: ArrayList<Gist>?): ArrayList<Gist>? {
return items
}
}
}
}
我试图从 this project 创建这个解决方案。但我的问题是 resultLiveData 在不等待网络调用响应的情况下一直在变化,因此响应的结果被忽略并且我的 ui 在数据到达之前被更新。由于 resultLiveData 在请求之前发生变化,因此还没有数据。简单地说,我如何观察分页列表的实时数据?
最后,我找到了一个可行的解决方案,但我认为这不是最佳解决方案。因此,如果您有任何想法,请不要犹豫回答。这是我的解决方案:
我放弃了包装 PagedList data with MediatorLiveData。我仍然将所有其他实时数据 (isLoadingLiveData, isEmptyLiveData, errorLiveData
) 保留为 MediatorLiveData
,但在我的要点 PagedList LiveData 初始化时添加了它们的源。这是代码:
private var gists: LiveData<PagedList<Gist>>? = null
private val userNameLiveData = MutableLiveData<String>()
val isLoadingLiveData = MediatorLiveData<Boolean>()
val isEmptyLiveData = MediatorLiveData<Boolean>()
val errorLiveData = MediatorLiveData<ErrorMessage>()
val allGistsLiveData: LiveData<PagedList<Gist>>
get() {
if (gists == null) {
gists = GistModel(NetManager(getApplication()), getApplication()).getYourGists(userNameLiveData.value!!).create(0,
PagedList.Config.Builder()
.setPageSize(Constants.PAGED_LIST_PAGE_SIZE)
.setInitialLoadSizeHint(Constants.PAGED_LIST_PAGE_SIZE)
.setEnablePlaceholders(Constants.PAGED_LIST_ENABLE_PLACEHOLDERS)
.build())
isLoadingLiveData.addSource(gists) { isLoadingLiveData.value = false }
isEmptyLiveData.addSource(gists) {
if (it?.size == 0) {
isEmptyLiveData.value = true
}
}
errorLiveData.addSource(gists) {
if (it == null) {
errorLiveData.value = ErrorMessage(errorCode = ErrorCode.GENERAL_ERROR)
}
}
}
}
return gists!!
}
fun setUserName(userName: String) {
isLoadingLiveData.value = true
userNameLiveData.value = userName
gists = null
allGistsLiveData
}
有更好的方法来做到这一点。看这个例子:
https://github.com/android/architecture-components-samples/tree/master/PagingWithNetworkSample
诀窍是在您的数据源中放入一个可变的实时数据,如下所示:
enum class NetworkState { LOADING, LOADED, FAILURE }
val networkState = MutableLiveData<NetworkState>()
override fun loadInitial(params: LoadInitialParams<String>, callback: LoadInitialCallback<String, OrderService.Resource>) {
networkState.post(NetworkState.LOADING)
ApiClient.listMyObjects(
onSuccess = { list ->
networkState.post(NetworkState.LOADED)
callback.onResult(list)
}
onFailure = {
networkState.post(NetworkState.FAILURE)
}
)
}
然后您可以通过以下方式收听您的分页列表和网络状态:
val myDataSource = MyDataSource.Factory().create()
myDataSource.toLiveData().observe(viewLifeCycle, Observer { pagedList ->
// Update your recycler view
myRecyclerViewAdapter.submitList(pagedList)
})
myDataSource.networkState.observe(viewLifeCycle, Observer { state ->
// Show errors, retry button, progress view etc. according to state
})