目录

Jetpack:Paging分页库之进度状态

引言

我们在数据加载的过程中需要用到进度组件(例如加载圈、进度条)来显示加载状态。Paging为此提供了一个非常优秀的适配器LoadStateAdapter来支持这些进度组件。 代码用的是谷歌官方的Demo。

挂载到PagingDataAdapater

我们在之前的文章中提到到PagingDataAdapater,它是用来给RecyclerView加载PaingData的。我们的LoadStateAdapter需要通过withLoadStateHeaderAndFooter挂载到PagingDataAdapater下。

1
2
3
4
5
6
mPagingDataAdapater.withLoadStateHeaderAndFooter {
    // 头部加载的适配器
    header = mLoadStateAdapter(mPagingDataAdapater),
    // 底部加载的适配器
    footer = mLoadStateAdapter(mPagingDataAdapater)
}

我们将PagingDataAdapter传入到LoadStateAdapater中,这样LoadStateAdapter就能拿到PagingDataAdapter的状态了。

LoadStateAdapter

然后就是适配器的常规操作,传入ViewHolder,绑定数据与视图。不过这里要注意的是:

  • 绑定的是LoadState
  • ViewHolderNetworkStateItemViewHolder。这是一个自定义的ViewHolder,用于存放进度组件。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class MyLoadStateAdapter(
        private val adapter: PostsAdapter
) : LoadStateAdapter<NetworkStateItemViewHolder>() {
    override fun onBindViewHolder(holder: NetworkStateItemViewHolder, loadState: LoadState) {
        holder.bindTo(loadState)
    }

    override fun onCreateViewHolder(
            parent: ViewGroup,
            loadState: LoadState
    ): NetworkStateItemViewHolder {
        return NetworkStateItemViewHolder(parent) { adapter.retry() }
    }
}

ViewHolder

布局文件network_state_item.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="vertical"
              android:padding="8dp">
    <TextView
        android:id="@+id/error_msg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>
    <ProgressBar
        android:id="@+id/progress_bar"
        style="?android:attr/progressBarStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>
    <Button
        android:id="@+id/retry_button"
        style="@style/Widget.AppCompat.Button.Colored"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="@string/retry"/>
</LinearLayout>

ViewHolder实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class NetworkStateItemViewHolder(
    parent: ViewGroup,
    private val retryCallback: () -> Unit
) : RecyclerView.ViewHolder(
    LayoutInflater.from(parent.context).inflate(R.layout.network_state_item, parent, false)
) {
    private val binding = NetworkStateItemBinding.bind(itemView)
    private val progressBar = binding.progressBar
    private val errorMsg = binding.errorMsg
    private val retry = binding.retryButton
        .also {
            it.setOnClickListener { retryCallback() }
        }

    fun bindTo(loadState: LoadState) {
        progressBar.isVisible = loadState is Loading
        retry.isVisible = loadState is Error
        errorMsg.isVisible = !(loadState as? Error)?.error?.message.isNullOrBlank()
        errorMsg.text = (loadState as? Error)?.error?.message
    }
}

我们在布局文件中放入了三个组件,分别是错误信息显示、加载圈、重试按钮。 我们在ViewHolder中的bindTo方法中,根据LoadState加载状态来改变组件的可见性从而实现加载效果。 这已经可以满足一般性的加载需求,你也可以根据自己的需要适当添加动画,来增强视觉观感。