Android Jetpack架构组件之 Paging(使用、源码篇)

本文详细介绍了Android Jetpack架构组件中的Paging组件,包括Paging的简介、使用步骤、与Room的结合、自定义DataSource以及源码分析。Paging组件能够实现分页加载,减少网络带宽消耗,提高应用响应速度。文章通过实例展示了如何配置Paging,如何在Room数据库中使用,以及如何自定义DataSource。此外,还探讨了Paging与RecyclerView的结合,以及如何通过RxJava2观察分页数据。最后,文章深入源码,解析了Paging的初始化加载、数据显示和下拉加载的实现逻辑。
摘要由CSDN通过智能技术生成

1、前言

最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面。

Android Architecture组件是Android Jetpack的一部分,它们是一组库,旨在帮助开发者设计健壮、可测试和可维护的应用程序,包含一下组件:

上述时Android Architecture所提供的架构组件,本文主要从使用和源码的角度分析Paging组件

2、Paging简介

  • 分页库概述
  1. Paging Library中DataSource,PagedList,PagedAdapter三者之间的关系以及数据加载到数据展示的流程

比如当一条新的item插入到数据库,DataSource会被初始化,LiveData后台线程就会创建一个新的PagedList。这个新的PagedList会被发送到UI线程的PagedListAdapter中,PagedListAdapter使用DiffUtil在对比现在的Item和新建Item的差异。当对比结束,PagedListAdapter通过调用RecycleView.Adapter.notifyItemInserted()将新的item插入到适当的位置

  • PagedList:是Paging Library的关键组件,它是一个异步加载应用程序数据块或页面的集合
  • Data
  1. 每个PagedList实例都会加载应用程序DataSource的最新数据
  2. 数据从应用程序的后端或数据库流入PagedList对象
  • UI:PagedList类与 PagedListAdapter一起加载 数据到RecyclerView中
  • Paging组件好处
  1. 分页库可以更轻松地在应用程序中的RecyclerView逐步和优雅地加载数据
  2. 数据请求消耗的网络带宽更少,系统资源更少
  3. 即使在数据更新和刷新期间,应用程序仍会继续快速响应用户输入

3、Paging组件的使用

3.1、添加依赖

def paging_version = "1.0.0"
implementation "android.arch.paging:runtime:$paging_version"
testImplementation "android.arch.paging:common:$paging_version"
implementation "android.arch.paging:rxjava2:1.0.0-rc1"

3.2、Paging使用步骤

  • 定义分页配置
  1. Page size :页面大小即每次加载时加载的数量
  2. Prefetch distance:预取距离,给定UI中最后一个可见的Item,超过这个item应该预取一段数据
  3. UI占位符:setEnablePlaceholders()
val myPagingConfig = PagedList.Config.Builder()       // 分页设置
        .setPageSize(50)
        .setPrefetchDistance(150)
        .setEnablePlaceholders(true)
        .build()
  • 使用分页配置创建LiveData<PagedList> ,传入DataSource.Factory,用于创建DataSource,从DataSource中加载数据到PagedList中
val concertList = LivePagedListBuilder(myConcertDataSource, myPagingConfig)
        .setFetchExecutor(myExecutor)
        .build()
  • 观察LiveData<PagedList>,在数据改变时调用适配器刷新数据
viewModel.concertList.observe(this, { pagedList ->
                adapter.submitList(pagedList) })

3.3、Paging和Room的使用

  • 在Room的@Dao中添加查询方法
@Dao
interface UserDao {
    @Query("SELECT * FROM user")
    fun getAll() : DataSource.Factory<Int,User>  // 返回DataSOurce.Factory配合PagingList使用
}
  • 在ViewModel中查询数据库并创建LiveData<PagedList>
class ViewModelUser(application: Application) : AndroidViewModel(application) {
      val dao = UserDataBase.getInstence(application)?.getDao()
传入Room返回的DataSource.Factory
      var liveArray : LiveData<PagedList<User>> = 
LivePagedListBuilder(dao!!.getAll(),PagedList.Config.Builder() 
              .setPageSize(10)
              .setPrefetchDistance(10)
              .setEnablePlaceholders(true)
              .build()).build()
}
  • 创建PagedListAdapter的实现类,加载并显示数据
class Adapter : PagedListAdapter<User, Adapter.UserViewHolder>(diffCallback) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
      return UserViewHolder(layoutInflater.inflate(R.layout.item,parent,false))
     }

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        val user = getItem(position)
        if (user != null){
            holder.bind(user)
        }else{
            holder.clear()
        }
      }

    companion object {
        val diffCallback = object : DiffUtil.ItemCallback<User>() {
            override fun areItemsTheSame(oldItem: User?, newItem: User?): Boolean {
              return  oldItem?.id == newItem?.id
            }
            override fun areContentsTheSame(oldItem: User?, newItem: User?): Boolean {
                return oldItem == newItem
               }
        }
    }
    class UserViewHolder(val view : View) :
            RecyclerView.ViewHolder(view){
        private val  tvId : TextView = view.findViewById(R.id.tvId)
        private val  tvName : TextView = view.findViewById(R.id.tvName)

        fun bind(user: User){
            tvId.text = user.id.toString()
            tvName.text = user.name
        }

        fun clear(){
            tvName.text = null
            tvId.text = null
        }
}

这里说一下传入的DiffUtil.ItemCallback<> 实例,当数据加载到PagedListAdapter时,会回调DiffUtil.ItemCallback中两个抽象方法,确认数据和之前是否发生了改变,如果改变则调用Adapter更新数据:

  1. areItemTheSame():是否为同一个Item
  2. areContentsTheSame():数据内容是否发生变化
  • 添加LiveData<PagedList>观察者
 val viewModel = ViewModelProviders.of(this).get(ConcertViewModel::class.java!!)
        val recyclerView = findViewById(R.id.concert
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值