安卓中实现分页加载方案(二)——paging基于ItemKeyedDataSource的加载方式
背景
组里在研究jetpeck库基于kotlin的使用,本次主要是研究paging的使用。
方案分析
paging的使用,基于ItemKeyedDataSource(PagedKeyUserDataSource )的加载方式目前已经是属于不被推荐的方案,不过还是写个总结记录下,会和后续推荐的方案进行对比。
实现方案
1、导入相关依赖
implementation "androidx.paging:paging-runtime-ktx:3.0.1"
testImplementation "androidx.paging:paging-common-ktx:3.0.1"
implementation "androidx.paging:paging-rxjava2-ktx:3.0.1"
2、创建实体类
class Concert {
var name: String? = null
var userId = 0
}
3、创建数据集
基于ItemKeyedDataSource的加载方式
class ConcertItemKeyedDataSource : ItemKeyedDataSource<Int, Concert>() {
private val TAG = "ItemKeyedDataSource";
var FIRST_PAGE = 1
val PAGE_SIZE = 20
/**
* 获取下一页的起始位置
*/
override fun getKey(item: Concert): Int {
return item.userId
}
/**
* 加载分页数据
*/
override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Concert>) {
Log.d(TAG, "正在请求第${FIRST_PAGE}数据")
val concertList = mutableListOf<Concert>()
val startPosition = FIRST_PAGE++ * PAGE_SIZE
for (i in startPosition..(startPosition + 19)) {
val concert = Concert()
concert.name = "jack$i"
concert.userId = i
concertList.add(concert)
}
callback.onResult(concertList)
}
/**
* 加载前执行方法
* 只会执行一次
*/
override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Concert>) {
Log.d(TAG, "请求第${FIRST_PAGE}数据")
}
/**
* 加载第一页数据
*/
override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Concert>) {
Log.d(TAG, "加载第一页数据")
val concertList = mutableListOf<Concert>()
for (i in 0..19) {
val concert = Concert()
concert.name = "jack$i"
concert.userId = i
concertList.add(concert)
}
callback.onResult(concertList)
}
}
4、生成数据
class ConcertFactory : DataSource.Factory<Int, Concert>() {
private var sourceLiveData: MutableLiveData<ConcertItemKeyedDataSource> = MutableLiveData()
override fun create(): DataSource<Int, Concert> {
val concertDataSource = ConcertItemKeyedDataSource()
sourceLiveData.postValue(concertDataSource)
return concertDataSource
}
}
5、使用ViewModel来处理数据
class ConcertViewModel : ViewModel() {
var convertList: LiveData<PagedList<Concert>>? = null
private var concertDataSource: DataSource<Int, Concert>? = null
init {
val concertFactory = ConcertFactory()
concertDataSource = concertFactory.create()
val config = PagedList.Config.Builder()
.setEnablePlaceholders(true).setPageSize(20).setPrefetchDistance(3).build()
convertList = LivePagedListBuilder(concertFactory, config).build()
}
}
6、使用adapter来显示数据
open class RecyclerViewAdapter: PagedListAdapter<Concert, RecyclerViewAdapter.RecyclerViewHolder>(DIFF_CALLBACK) {
inner class RecyclerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val tv: TextView = view.findViewById(R.id.tv_content)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.adapter_paging, parent, false)
return RecyclerViewHolder(view)
}
override fun onBindViewHolder(holder: RecyclerViewHolder, position: Int) {
val concert = getItem(position)
if (concert != null) {
holder.tv.text = concert.name
}
}
companion object {
private val DIFF_CALLBACK: DiffUtil.ItemCallback<Concert> = object : DiffUtil.ItemCallback<Concert>() {
override fun areItemsTheSame(oldConcert: Concert, newConcert: Concert): Boolean {
return oldConcert.name == newConcert.name
}
override fun areContentsTheSame(oldConcert: Concert, newConcert: Concert): Boolean {
return oldConcert.equals(newConcert)
}
}
}
}
7、在activity中实现功能
class PagingActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_paging)
val adapter = RecyclerViewAdapter()
val viewModel: ConcertViewModel = ViewModelProvider(this).get(ConcertViewModel::class.java)
concert_list.adapter = adapter
concert_list.layoutManager = LinearLayoutManager(this)
viewModel.convertList?.observe(this, Observer {
adapter.submitList(it)
})
}
}
8、activity对应的xml布局文件如下
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.PagingActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/concert_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
9、adapter中对应的item布局如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_gravity="center_horizontal"
android:layout_height="wrap_content">
<TextView
android:layout_gravity="center_horizontal"
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>