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

后端 未结 3 1334
离开以前
离开以前 2021-01-01 22:58
  • How to determine size of data returned before setting adapter?
  • How to use emptyview with paging library?
  • How to set emptyview if pagedlist returns n
相关标签:
3条回答
  • 2021-01-01 23:41

    Simply add a listener or callback function to your DataSourceFactory and your DataSource and call it if the list in loadInitial is empty:

    class DataSourceFactory(
        private val dataObservable: Observable<List<Data>>,
        private val onEmptyAction: () -> Unit
    ) : DataSource.Factory<Int, Data >() {
    
         override fun create(): DataSource {
             return DataSource(observable, onEmptyAction)
         }
    }
    
    class DataSource(
        private val observable: Observable<List<Data>>,
        private val onEmptyAction: () -> Unit
    ) : ItemKeyedDataSource<Int, Data>() {
    
        private val data = mutableListOf<Data>()
    
        override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Data>) {
            observable
                .subscribe({ data ->
                    if (data.isEmpty()) {
                        // Inform someone that this list is empty from the
                        // beginning to be able to show an empty page
                        onEmptyAction()
                    }
    
                    // rest of your code & logic
            }, { Timber.e(it) })
        }
    }
    
    0 讨论(0)
  • 2021-01-01 23:42

    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

    0 讨论(0)
  • 2021-01-01 23:47

    In your fragment/activity you are observing network state:

    viewModel.getNetworkState1()?.observe(this, Observer {
                    // here you can handle you empty view 
                    setEmptyView()
    
                })
    

    like this:

    private fun setNoTransactionsLayout() {
        if(viewModel.listIsEmpty()) {
            yourTextView.visibility = View.VISIBLE
        } else {
            yourTextView.visibility = View.GONE
        }
    }
    

    And in view model you have this function:

    fun listIsEmpty(): Boolean {
        return yourPagedList?.value?.isEmpty() ?: true
    }
    
    0 讨论(0)
提交回复
热议问题