Progressbar and error message with Paging Library
Asked Answered
S

2

9

Paging Library is amazing. But I find that lacks this features:

  • Dispatch a view when data is loading. Assuming I am extending PageKeyedDataSource: a view on top when loadInitial is called, a view on bottom of the list when loadAfter is called. Views should disappear when callback is invoked.
  • Dispatch a view when there is an error.
  • Swipe to refresh

As this is not possible right now, does anyone know a way to do it using PagingLibrary? At least a way to use different views in the same list.

Supersensible answered 9/1, 2018 at 17:29 Comment(0)
I
5

There is great sample @yigit related to the Paging library which also shows how to handle progress bar, error and Retry in Recyclerview. So Basically he is creating a Listing.kt data class which consist of the NetworkState and PagedList Like below

Listing.kt

data class Listing<T>(
        // the LiveData of paged lists for the UI to observe
        val pagedList: LiveData<PagedList<T>>,
        // represents the network request status to show to the user
        val networkState: LiveData<NetworkState>,
        // represents the refresh status to show to the user. Separate from networkState, this
        // value is importantly only when refresh is requested.
        val refreshState: LiveData<NetworkState>,
        // refreshes the whole data and fetches it from scratch.
        val refresh: () -> Unit,
        // retries any failed requests.
        val retry: () -> Unit)

NetworkState.kt

enum class Status {
    RUNNING,
    SUCCESS,
    FAILED
}

@Suppress("DataClassPrivateConstructor")
data class NetworkState private constructor(
        val status: Status,
        val msg: String? = null) {
    companion object {
        val LOADED = NetworkState(Status.SUCCESS)
        val LOADING = NetworkState(Status.RUNNING)
        fun error(msg: String?) = NetworkState(Status.FAILED, msg)
    }
}

RedditPostRepository.kt

interface RedditPostRepository {
    fun postsOfSubreddit(subReddit: String, pageSize: Int): Listing<RedditPost>

    enum class Type {
        IN_MEMORY_BY_ITEM,
        IN_MEMORY_BY_PAGE,
        DB
    }
}

The SubRedditViewModel.k observe the Listing<RedditPost> from RedditPostRepository.kt notify to UI about the state and data and UI updates the view accordingly. To know more about how the NetworkState propagate from Datasource to ViewModel Look at the PageKeyedSubredditDataSource.kt and SubRedditDataSourceFactory.kt

Here is the Link to the Google sample by @yigit.

Isolde answered 13/5, 2018 at 10:6 Comment(2)
Broken link for SubRedditDataSourceFactory.ktRobbegrillet
I just looked at the class. Why didn't he use sealed class instead of enums? hmm...Bickerstaff
A
0

The main idea is to keep a reference to the data source that is created by the data source factory. below is a code snippet from https://github.com/googlesamples/android-architecture-components/tree/master/PagingWithNetworkSample

class SubRedditDataSourceFactory(
    private val redditApi: RedditApi,
    private val subredditName: String,
    private val retryExecutor: Executor) : DataSource.Factory<String, 
RedditPost>() {
    val sourceLiveData = MutableLiveData<PageKeyedSubredditDataSource>()
    override fun create(): DataSource<String, RedditPost> {
        val source = PageKeyedSubredditDataSource(redditApi, subredditName, 
retryExecutor)
        sourceLiveData.postValue(source)
        return source
   }
}

in this code example, 'sourceLiveData' publishes the active data source. the data source in turn, can expose all the relevant information to the view like network state and an indicator if first load is completed

in order to add refresh behavior wrap the recycler view with SwipeRefreshLayout as shown below. now that you have access to the data source you can invalidate it and the view will be refreshed

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh"
                                              android:layout_width="match_parent"
                                              android:layout_height="match_parent">
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        app:layoutManager="LinearLayoutManager"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
Alit answered 12/11, 2018 at 12:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.