1、前言
最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面。
Android Architecture组件是Android Jetpack的一部分,它们是一组库,旨在帮助开发者设计健壮、可测试和可维护的应用程序,包含一下组件:
- 带你领略Android Jetpack组件的魅力
- Android Jetpack 架构组件之 Lifecycle(使用篇)
- Android Jetpack 架构组件之 Lifecycle(源码篇)
- Android Jetpack 架构组件之 ViewModel (源码篇)
- Android Jetpack 架构组件之 LiveData(使用、源码篇)
- Android Jetpack架构组件之 Paging(使用、源码篇)
- Android Jetpack 架构组件之 Room(使用、源码篇)
- Android Jetpack 架构组件之Navigation
- Android Jetpack架构组件之WorkManger
- 实战:从0搭建Jetpack版的WanAndroid客户端
上述时Android Architecture所提供的架构组件,本文主要从使用和源码的角度分析Paging组件
2、Paging简介
- 分页库概述
- 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
- 每个PagedList实例都会加载应用程序DataSource的最新数据
- 数据从应用程序的后端或数据库流入PagedList对象
- UI:PagedList类与 PagedListAdapter一起加载 数据到RecyclerView中
- Paging组件好处
- 分页库可以更轻松地在应用程序中的RecyclerView逐步和优雅地加载数据
- 数据请求消耗的网络带宽更少,系统资源更少
- 即使在数据更新和刷新期间,应用程序仍会继续快速响应用户输入
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使用步骤
- 定义分页配置
- Page size :页面大小即每次加载时加载的数量
- Prefetch distance:预取距离,给定UI中最后一个可见的Item,超过这个item应该预取一段数据
- 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更新数据:
- areItemTheSame():是否为同一个Item
- areContentsTheSame():数据内容是否发生变化
- 添加LiveData<PagedList>观察者
val viewModel = ViewModelProviders.of(this).get(ConcertViewModel::class.java!!)
val recyclerView = findViewById(R.id.concert