参考文章 更应该说是 java kotlin的翻版
需要添加的库
def fragment_version = "1.3.3"
def lifecycle_version = "2.3.1"
// Java language implementation
implementation "androidx.fragment:fragment:$fragment_version"
// Kotlin
implementation "androidx.fragment:fragment-ktx:$fragment_version"
// Testing Fragments in Isolation
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
def activity_version = "1.2.3"
// Java language implementation
implementation "androidx.activity:activity:$activity_version"
// Kotlin
implementation "androidx.activity:activity-ktx:$activity_version"
implementation "androidx.paging:paging-runtime:2.1.0" //2.0
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
// Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
// Jetpack Compose Integration for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha04"
// Annotation processor
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// optional - helpers for implementing LifecycleOwner in a Service
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
// optional - ReactiveStreams support for LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
//网络库
compile 'com.lzy.net:okgo:3.0.4'
// gson解析
implementation 'com.google.code.gson:gson:2.8.7'
数据类
ArticleResponse
data class ArticleResponse(
val `data`: Data,
val errorCode: Int,
val errorMsg: String
)
Data
data class Data(
val curPage: Int,
val datas: List<DataX>,
val offset: Int,
val over: Boolean,
val pageCount: Int,
val size: Int,
val total: Int
)
DataX
data class DataX(
val apkLink: String,
val audit: Int,
val author: String,
val canEdit: Boolean,
val chapterId: Int,
val chapterName: String,
val collect: Boolean,
val courseId: Int,
val desc: String,
val descMd: String,
val envelopePic: String,
val fresh: Boolean,
val host: String,
val id: Int,
val link: String,
val niceDate: String,
val niceShareDate: String,
val origin: String,
val prefix: String,
val projectLink: String,
val publishTime: Long,
val realSuperChapterId: Int,
val selfVisible: Int,
val shareDate: Long,
val shareUser: String,
val superChapterId: Int,
val superChapterName: String,
val tags: List<Tag>,
val title: String,
val type: Int,
val userId: Int,
val visible: Int,
val zan: Int
)
Tag
data class Tag(
val name: String,
val url: String
)
ViewModel
PagindViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.paging.DataSource
import androidx.paging.LivePagedListBuilder
import androidx.paging.PageKeyedDataSource
import androidx.paging.PagedList
import com.google.gson.Gson
import com.lzy.okgo.OkGo
import com.lzy.okgo.callback.StringCallback
import com.lzy.okgo.model.Response
import com.www.jetpackui.paging2.bean.bean1.ArticleResponse
import com.www.jetpackui.paging2.bean.bean1.DataX
/**
*@time:
*@author yulai
*/
class PagindViewModel : ViewModel() {
private val TAG = PagindViewModel::class.java
private lateinit var articleRes: LiveData<PagedList<DataX>>
private lateinit var mDataSource: ArticleDataSource //如果使用lateinit的话下面直接使用会报错的
// //这是lzay的使用
// val articleTestRes:List<String> by lazy {
//
// listOf("a","b")
// }
//边界数据是否有数据
private val boundaryPageData = MutableLiveData<Boolean>() //注意这里的泛型是boolean 因为要么 有数据 要么没有数据 如果有二种以上的情况下的话可以使用其它类型
fun getArticleLiveData(): LiveData<PagedList<DataX>>? {
if (articleRes == null) {
//在这里要用articleRes 因为没有被初使化所以直接会报错的
val config = PagedList.Config.Builder()
.setPageSize(20)
.setInitialLoadSizeHint(22)
.build()
articleRes = LivePagedListBuilder<Int, DataX>(mFactory, config)
.setBoundaryCallback(mBoundaryCallback).build()
}
return articleRes
}
fun getBoundaryPageData(): MutableLiveData<Boolean> {
return boundaryPageData
}
val mFactory = object : DataSource.Factory<Int, DataX>() {
override fun create(): DataSource<Int, DataX> {
//因为mDataSource要使用而没有被初使化 也会报错
if (mDataSource == null || mDataSource.isInvalid) {
mDataSource = ArticleDataSource()
}
return mDataSource
}
}
//边界数据监听
var mBoundaryCallback: PagedList.BoundaryCallback<DataX> = object : PagedList.BoundaryCallback<DataX>() {
override fun onZeroItemsLoaded() {
super.onZeroItemsLoaded()
//初始化数据
boundaryPageData.postValue(false)
}
override fun onItemAtEndLoaded(itemAtEnd: DataX) {
super.onItemAtEndLoaded(itemAtEnd)
//正在添加数据
boundaryPageData.postValue(true)
}
override fun onItemAtFrontLoaded(itemAtFront: DataX) {
super.onItemAtFrontLoaded(itemAtFront)
//没有数据加载了
boundaryPageData.postValue(false)
}
}
//两个参数 一个是 initalCallback 一个是callback 有什么区别呢
fun loadData(currentPage: Int, initalCallback: PageKeyedDataSource.LoadInitialCallback<Int, DataX>?, callback: PageKeyedDataSource.LoadCallback<Int, DataX>?) {
val url = "https://www.wanandroid.com/article/list/$currentPage/json";
OkGo.get<String>(url).execute(object : StringCallback() {
override fun onSuccess(response: Response<String>?) {
val gson = Gson()
val articleResponse: ArticleResponse = gson.fromJson(response?.body(), ArticleResponse::class.java) //拿数据后后通过json和我们的实体类映射
if (initalCallback != null) {
initalCallback.onResult(articleResponse.data.datas, -1, 0)
} else {
callback?.onResult(articleResponse.data.datas, currentPage)
}
boundaryPageData.postValue(articleResponse.data.datas.size <= 0) //<=0是没有数据 如果是true没有数据 如果是false有数据
}
})
}
//在这里发送网络请求
inner class ArticleDataSource : PageKeyedDataSource<Int, DataX>() {
override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, DataX>) {
//开始加载数据
loadData(0, callback, null)
}
override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, DataX>) {
//往后加载数据 上拉加载更多
loadData(params.key + 1, null, callback)
}
override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, DataX>) {
//往前加载数据 下拉刷新
}
}
}
页面Activity
ListActivity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.www.jetpackui.R
import com.www.jetpackui.paging2.adapter.PagingAdapter
import kotlinx.android.synthetic.main.activity_list.*
class ListActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list)
recyclerview.layoutManager = LinearLayoutManager(this,RecyclerView.VERTICAL,false)
val adapter = PagingAdapter()
recyclerview.adapter = adapter
var viewModel = ViewModelProvider(this, object : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return PagindViewModel() as T
}
}).get(PagindViewModel::class.java)
viewModel.getArticleLiveData()!!.observe(this, Observer { datas->
adapter.submitList(datas)
})
viewModel.getBoundaryPageData().observe(this, object : Observer<Boolean> {
override fun onChanged(t: Boolean) {
if(t){
Toast.makeText(this@ListActivity,"到底了",Toast.LENGTH_SHORT).show()
}
}
})
}
}
布局文件
activity_list.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=".paging2.ListActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
条目
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
android:divider="@color/black"
android:showDividers="end"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="80dp">
<TextView
android:gravity="center"
tools:text="使用Paging框架就必须要继承PagedListAdapter了,
它强制要求传入一个DiffUtil.ItemCallback,它是用来对新旧数据之间进行差分计算"
android:layout_margin="10dp"
android:id="@+id/tvname"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"></TextView>
</LinearLayout>