终究没有人在意一家民营企业的生死

去泰国看了一场“成人秀”,画面尴尬到让人窒息.....

网友建议:远离举报者李X夫!

【少儿禁】马建《亮出你的舌苔或空空荡荡》

10部适合女性看的唯美情色电影

生成图片,分享到微信朋友圈

自由微信安卓APP发布,立即下载! | 提交文章网址
查看原文

在 Compose 中使用 Paging 分页库 | 开发者说·DTalk

The following article is from Android技术圈 Author 黄林晴

本文原作者: 黄林晴原文发布于: Android技术圈

本篇文章主要来看在 Compose 中如何使用 Paging 3,这里不得不说一句,在 xml 中使用 Paging 3 和在 Compose 中使用仅有 UI 层代码不同,所以之前定义的接口层、仓库层直接复用代码即可。



Paging 3 的使用



项目搭建


首先,我们新建项目,在 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 接口准备


这里我们已经写好了 RetrofitService 类用于创建网络请求的 service 代码如下所示:
object RetrofitService {

/** * okhttp client */ lateinit var okHttpClient: OkHttpClient
/** * 主Url地址 */ private const val BASEAPI = "https://www.wanandroid.com/";

/** * 创建service对象 */ fun <T> createService(mClass: Class<T>): 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<Int,DemoReqData.DataBean.DatasBean>(){ override suspend fun load(params: LoadParams<Int>): LoadResult<Int, DemoReqData.DataBean.DatasBean> { TODO("Not yet implemented") }
override fun getRefreshKey(state: PagingState<Int, DemoReqData.DataBean.DatasBean>): Int? { return null }}


getRefreshKey 方法是新增的,之前没有提到过,这里讲解一下这个方法的用途。


getRefreshKey

getRefreshKey 方法意思是 refresh 时,从最后请求的页面开始请求,null 则请求第一页。


举个例子,请求出错时会调用 refresh 方法加载,如果当前已经请求了第一页到第四页的数据,可以通过设置在 refresh 后会加载第 5 - 8 页的数据,并且前四页的数据都没了。如果 getRefreshKey 返回 null,refresh 后会重新加载第一到第四页的数据,这里我们直接返回 null 即可。

DataSource 为我们自动生成了 load 方法,我们主要的请求操作就在 load 方法中完成。主要代码如下所示:
class ADataSource : PagingSource<Int, DemoReqData.DataBean.DatasBean>() { override suspend fun load(params: LoadParams<Int>): LoadResult<Int, DemoReqData.DataBean.DatasBean> {
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, DemoReqData.DataBean.DatasBean>): 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 函数,代码如下所示:

@Composablefun 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}") } }}


运行程序,结果下图所示。



监听 Paging 3 状态



这里我们以 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 即可。

完整代码如下所示:
@Composablefun 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, "网络未连接,其他异常") } } } } }

}
@Composablefun 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 中使用分页库的功能了。

源码地址已上传:

https://github.com/huanglinqing123/ComposePagingDemo




长按右侧二维码

查看更多开发者精彩分享




"开发者说·DTalk" 面向中国开发者们征集 Google 移动应用 (apps & games) 相关的产品/技术内容。欢迎大家前来分享您对移动应用的行业洞察或见解、移动开发过程中的心得或新发现、以及应用出海的实战经验总结和相关产品的使用反馈等。我们由衷地希望可以给这些出众的中国开发者们提供更好展现自己、充分发挥自己特长的平台。我们将通过大家的技术内容着重选出优秀案例进行谷歌开发技术专家 (GDE) 的推荐。




 点击屏末 | 阅读原文 | 即刻报名参与 "开发者说·DTalk" 




文章有问题?点此查看未经处理的缓存