androidkotlinpaginationmvpandroid-paging-library

How to use empty view with pagination using paging library android?



Solution

  • Update[24/04/19]: I just found out that the library already provide us a way to listen to empty initial load, using PagedList.BoundaryCallback<YourItem>.

    *Note that my old answer is still a valid alternative.

    val livedPageList = LivePagedListBuilder(sourceFactory, config)
            .setBoundaryCallback(object: PagedList.BoundaryCallback<YourItem>() {
                override fun onZeroItemsLoaded() {
                    super.onZeroItemsLoaded()
                    // Handle empty initial load here
                }
    
                override fun onItemAtEndLoaded(itemAtEnd: YourItem) {
                    super.onItemAtEndLoaded(itemAtEnd)
                    // Here you can listen to last item on list
                }
    
                override fun onItemAtFrontLoaded(itemAtFront: YourItem) {
                    super.onItemAtFrontLoaded(itemAtFront)
                    // Here you can listen to first item on list
                }
            })
            .build()
    

    Original Answer:

    Based on this class on google sample Network State. Modify it to handle empty content in initialLoad.

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

    Usage as follow:

    class DataSource: PageKeyedDataSource<Long, Item>() {
    
        val initialLoad: MutableLiveData<NetworkState> = MutableLiveData()
    
        override fun loadInitial(params: LoadInitialParams<Long>, callback: LoadInitialCallback<Long, Item>) {
            initialLoad.postValue(NetworkState.LOADING)
            apiCallSource.subscribe({ items ->
                if (items.isEmpty()) {
                    initialLoad.postValue(NetworkState.EMPTY)
                } else {
                    initialLoad.postValue(NetworkState.LOADED)
                }
            }, { error -> 
                // handle error
            })
        }
    }
    

    And this is how the activity handle it:

    class activity: AppCompatActivity() {
    
        val viewModel = // init viewmodel
    
        override fun onCreate(savedInstanceState: Bundle?) {
            viewModel.refreshState.observe(this, Observer { networkState ->
                if (it == NetworkState.LOADING) {
                    // Show loading
                } else {
                    // Hide loading
    
                    if (it.status == NetworkState.Status.SUCCESS_EMPTY) {
                        // Show empty state for initial load
                    }
                }
            }
        }
    }
    

    For more details on how to connect DataSource with Activity, see this sample