代码之家  ›  专栏  ›  技术社区  ›  melomg

如何观察页面列表数据?

  •  2
  • melomg  · 技术社区  · 7 年前

    我正在使用 Paging Library 和Android架构组件。我只是想观察页面列表的实时数据,并在有变化时更新我的RecyclerView。

    我正在观察isLoadingLiveData、isEmptyLiveData和errorLiveData对象,它们是在我的ViewModel中创建的中介LiveData对象,在我的片段中观察到。还观察resultLiveData,它返回从远程获取的Gist列表。

    在我的ViewModel中,我创建了一个页面列表LiveData,每当它的数据发生更改时,我都想更新isLoadingLiveData、isEmptyLiveData、errorLiveData和 PagedListAdapter . 因此,我将isLoadingLiveData、isEmptyLiveData、errorLiveData和resultLiveData定义为MediatorLiveData对象。我添加了resultLiveData作为这些对象的源。因此,当resultLiveData发生更改时,将调用这些对象的onChanged方法。resultLiveData依赖于userNameLiveData,因此当userNameLiveData发生更改时,将调用AllGistLiveData并获取数据。例如,当用户滑动列表时,我设置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))
    }
    

    我的remoteDataSource:

    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在请求之前发生更改,因此还没有数据。简单地说,我如何观察页面列表的实时数据?

    2 回复  |  直到 7 年前
        1
  •  1
  •   melomg    7 年前

    最后,我找到了一个可行的解决方案,但我认为这不是最好的解决方案。因此,如果你有任何想法,请毫不犹豫地回答。以下是我的解决方案:

    我放弃了包装我的 PagedList 具有的数据 MediatorLiveData . 我仍然保留所有其他实时数据( isLoadingLiveData, isEmptyLiveData, errorLiveData )作为 MediatorLiveData 但在我的gists 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
    }
    
        2
  •  0
  •   Allan Veloso Vineeth Reddy    4 年前

    有更好的方法可以做到这一点。看看这个例子:

    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  
    })