大约在两年前,写了一篇Jetpack 系列之Paging3,看这一篇就够了~,本篇文章主要来看,在Compose中如何使用Paging3,这里不得不说一句,在xml中使用Paging3和在Compose中使用仅有UI层代码不同,所以之前定义的接口层、仓库层直接复用直接的代码即可。
Paging3的使用 项目搭建首先,我们新建项目,在build.gradle中引入compose的paging库,这里将网络请求等依赖库一并引入。代码如下所示:
implementation("androidx.paging:paging-compose:1.0.0-alpha14")
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.9.2"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1"
API接口准备
API接口我们使用 「鸿洋」大佬 「玩Android」中的查询每日一问接口 :https://wanandroid.com/wenda/list/1/json
这里我们已经写好了RetrofitService类用于创建网络请求的service代码如下所示:
object RetrofitService {
/**
* okhttp client
*/
lateinit var okHttpClient: OkHttpClient
/**
* 主Url地址
*/
private const val BASEAPI = "https://www.wanandroid.com/";
/**
* 创建service对象
*/
fun createService(mClass: Class): T {
val builder: OkHttpClient.Builder = OkHttpClient.Builder();
okHttpClient = builder.build()
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(BASEAPI)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
return retrofit.create(mClass) as T
}
}
定义DataApi接口,这里我们将方法声明为挂起函数,代码如下所示:
interface DataApi {
/**
* 获取数据
*/
@GET("wenda/list/{pageId}/json")
suspend fun getData(@Path("pageId") pageId:Int): DemoReqData
}
定义数据源
首先我们来定义数据源DataSource继承自PagingSource,代码如下所示:
class DataSource():PagingSource(){
override suspend fun load(params: LoadParams): LoadResult {
TODO("Not yet implemented")
}
override fun getRefreshKey(state: PagingState): Int? {
return null
}
}
这里具体的含义已经在上篇Paging3文章中讲的很详细了,getRefreshKey方法是新增的,之前没有提到过,这里讲解一下这个方法的用途。
getRefreshKeygetRefreshKey方法意思是 refresh时,从最后请求的页面开始请求,null则请求第一页。
举个例子,请求出错时会调用refresh方法加载 ,如果当前已经请求了第一页到第四页的数据, 可以通过设置在refresh 后会加载第5 - 8页的数据,并且前四页的数据都没了。如果getRefreshKey返回null,refresh后 会重新加载第一到第四页的数据,这里我们直接返回null即可。
DataSource为我们自动生成了load方法,我们主要的请求 *** 作就在load方法中完成。主要代码如下所示:
class ADataSource : PagingSource() {
override suspend fun load(params: LoadParams): LoadResult {
return try {
//页码未定义置为1
val currentPage = params.key ?: 1
//仓库层请求数据
Log.d("请求页码标记", "请求第${currentPage}页")
val demoReqData = DataRespority().loadData(currentPage)
//当前页码 小于 总页码 页面加1
val nextPage = if (currentPage < demoReqData.data?.pageCount ?: 0) {
currentPage + 1
} else {
//没有更多数据
null
}
LoadResult.Page(
data = demoReqData.data!!.datas!!,
prevKey = null,
nextKey = nextPage
)
} catch (e: Exception) {
if (e is IOException) {
Log.d("测试错误数据", "-------连接失败")
}
Log.d("测试错误数据", "-------${e.message}")
LoadResult.Error(throwable = e)
}
}
override fun getRefreshKey(state: PagingState): Int? {
return null
}
}
接下来我们看下DataRespority仓库层的代码,代码比较简单,如下所示:
class DataRespority {
private var netWork = RetrofitService.createService(
DataApi::class.java
)
/**
* 查询护理数据
*/
suspend fun loadData(
pageId: Int
): DemoReqData? {
return try {
netWork.getData(pageId)
} catch (e: Exception) {
//在这里处理或捕获异常
null
}
}
}
创建viewmodel
创建viewModel对象,并创建pager对象从而调用PagingSource方法 ,代码如下所示:
class MainActivityViewModel : ViewModel() {
/**
* 获取数据
*/
fun getData() = Pager(PagingConfig(pageSize = 1)) {
DataSource()
}.flow
}
到这里为止,上面的代码都和我们上篇文章中的代码是一致的,接下来我们主要看UI层的代码如何实现。
实现UI层代码 View层数据请求并将结果显示在View上val mainViewmodel: MainActivityViewModel = viewModel()
val data = mainViewmodel.getData().collectAsLazyPagingItems()
首先我们获取viewmodel的示例,这里可以调用viewModel函数需要引入lifecycle-viewmodel-compose库,代码如下所示:
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1"
通过调用collectAsLazyPagingItems方法将结果转为LazyPagingItems实例,在LazyColumn直接调用即可,代码如下所示:
Column {
LazyColumn() {
items(items = data) { item ->
Message(data = item)
}
}
}
Message是数据展示页面对应的compose函数,代码如下所示:
@Composable
fun Message(data: DemoReqData.DataBean.DatasBean?) {
Card(
modifier = Modifier
.background(Color.White)
.padding(10.dp)
.fillMaxSize(), elevation = 10.dp
) {
Column(modifier = Modifier.padding(10.dp)) {
Text(
text = "作者:${data?.author}"
)
Text(text = "${data?.title}")
}
}
}
运行程序,结果下图所示。
监听Paging3状态这里我们以refresh时加载为例,代码如下所示:
if (data.loadState.refresh is LoadState.Loading) {
Log.d(TAG, "正在加载")
} else if (data.loadState.refresh is LoadState.Error) {
when ((data.loadState.refresh as LoadState.Error).error) {
is IOException -> {
Log.d(TAG, "网络未连接,可在这里放置失败视图")
}
else -> {
Log.d(TAG, "网络未连接,其他异常")
}
}
}
断开网络,运行程序,打印如下图所示:
这里放置失败视图我们就不再演示了,如果想在失败时刷新的话,直接调用 data.refresh即可。
完整代码如下所示:
@Composable
fun Greeting() {
val mainViewmodel: MainActivityViewModel = viewModel()
val data = mainViewmodel.getData().collectAsLazyPagingItems()
Column {
LazyColumn() {
items(items = data) { item ->
Message(data = item)
}
val TAG = "加载状态"
if (data.loadState.refresh is LoadState.Loading) {
Log.d(TAG, "正在加载")
} else if (data.loadState.refresh is LoadState.Error) {
when ((data.loadState.refresh as LoadState.Error).error) {
is IOException -> {
Log.d(TAG, "网络未连接,可在这里放置失败视图")
}
else -> {
Log.d(TAG, "网络未连接,其他异常")
}
}
}
}
}
}
@Composable
fun Message(data: DemoReqData.DataBean.DatasBean?) {
Card(
modifier = Modifier
.background(Color.White)
.padding(10.dp)
.fillMaxSize(), elevation = 10.dp
) {
Column(modifier = Modifier.padding(10.dp)) {
Text(
text = "作者:${data?.author}"
)
Text(text = "${data?.title}")
}
}
}
这样我们就实现了,在Compose中使用分页库的功能了。
源码地址已上传
源码地址:GitHub - huanglinqing123/ComposePagingDemo: Compose中使用Paging3分页库示例
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)