Android Compose——Paging3
创始人
2024-05-11 10:10:45

Paging3

  • 效果视频
  • 简述
  • Hilt+Retrofit
    • 访问接口
    • 网络实例
  • PagingSource
  • ViewModel
  • View

效果视频

简述

本Demo采用Hilt+Retrofit+Paging3完成,主要为了演示paging3分页功能的使用,下列为Demo所需要的相关依赖

 //retrofitimplementation 'com.squareup.retrofit2:retrofit:2.9.0'implementation 'com.squareup.retrofit2:converter-gson:2.9.0'//pagingimplementation 'androidx.paging:paging-runtime:3.1.1'implementation 'androidx.paging:paging-compose:1.0.0-alpha14'//Dagger - Hiltimplementation("com.google.dagger:hilt-android:2.44")kapt("com.google.dagger:hilt-android-compiler:2.44")// Compose dependenciesimplementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1"implementation "androidx.hilt:hilt-navigation-compose:1.0.0"// Coroutinesimplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1'implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'

Hilt+Retrofit

访问接口

定义需要访问的接口,此接口是Github api,suspend字段用于提示后续引用,此内容需要在协程中使用

interface GithubService {@GET("search/repositories?sort=stars&q=Android")suspend fun queryGithubAsync(@Query("per_page")number:Int, @Query("page") page:Int):DetailsBean
}

网络实例

提供三个实例,最终外部需要引用的的为UseCase的实例,具体Hilt依赖注入此处不予说明,有意者可参考Hilt依赖注入

@Module
@InstallIn(SingletonComponent::class)
object AppModule {const val BASE_URL:String = "https://api.github.com/"@Singleton@Providesfun providerRetrofit():Retrofit{return Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build()}@Singleton@Providesfun providerGithubService(retrofit: Retrofit): GithubService {return retrofit.create(GithubService::class.java)}@Singleton@Providesfun providerUseCase(service: GithubService):UseCase{return UseCase(GetProjects(service))}
}

在Hilt提供的实例中,UseCase中实现了访问网络接口的任务

data class UseCase(val getProjects: GetProjects
)
class GetProjects(private val service: GithubService) {suspend operator fun invoke(number:Int,page:Int): DetailsBean {return service.queryGithubAsync(number, page)}
}

PagingSource

我们主要实现load方法;其中page为当前内容页数,pageSize为每页需要加载的内容数量(可在外部进行定义),repository为获取的网络数据实体,previousPage为前一页,此处做了一个判断,如果为第一页时,则返回null,否则进行滑动至上一页;nextPage为下一页, LoadResult.Page为分页加载所需的内容; LoadResult.Error可捕获异常

class DataPagingSource(private val useCase: UseCase):PagingSource() {override fun getRefreshKey(state: PagingState): Int? = nulloverride suspend fun load(params: LoadParams): LoadResult {return try {val page = params.key ?: 1 //当前页,默认第一页val pageSize = params.loadSize //每页数据条数val repository = useCase.getProjects(page,pageSize) //获取的数据源val repositoryItem = repository.beans //获取的数据列表val previousPage = if (page > 1) page - 1 else null //前一页val nextPage = if (repositoryItem.isNotEmpty()) page+1 else null //下一页Log.d("hiltViewModel","page=$page size=$pageSize")LoadResult.Page(repositoryItem,previousPage,nextPage)}catch (e:Exception){LoadResult.Error(e)}}
}

ViewModel

在构造函数中调用Hilt构造的实例;其中getData方法为获取分页的数据,返回为Flow>类型,其中Flow>外部为固定写法,内部可根据需要自行定义,然后PagingConfig的配置中,我们需要配置pageSizeinitialLoadSize,如果不定义后者,则通过每页内容数量会是pageSize的三倍,然后添加我们上述创建的PagingSource;最后转化为流,然后置于协程中,它缓存PagingData,以便此流的任何下游集合都将共享相同的数据

@HiltViewModel
class HomeViewModel @Inject constructor(private val useCase: UseCase):ViewModel() {val PAGE_SIZE = 10fun getData():Flow>{return Pager(config = PagingConfig(pageSize = PAGE_SIZE, initialLoadSize = PAGE_SIZE),pagingSourceFactory = { DataPagingSource(useCase) }).flow.cachedIn(viewModelScope)}
}

View

获取ViewModel中的数据

  val datas = viewModel.getData().collectAsLazyPagingItems()

同时如果需要添加底部刷新状态栏、数据错误等标识,需要监听loadState,其状态总共分为五种:

  • refresh:第一次加载数据触发
  • prepend:滑动上一页触发
  • append:滑动下一页触发
  • source:对应于[PagingSource]中的加载
  • mediator:对应于来自[RemoteMediator]的加载
    我们此处主要使用refreshappend
    其中,在refresh中进行监听,如果然后数据为null,则显示全屏错误提示,此处为第一次加载数据;
    然后,在append中监听loadingError两种状态,在其loading是显示底部加载状态,在Error中显示底部错误提示,此处不同于refreshError状态,因为有了数据,就不在需要显示全屏错误提示,在数据列表底部显示错误状态栏即可

@Composable
fun GithubList(viewModel: HomeViewModel = hiltViewModel()){val datas = viewModel.getData().collectAsLazyPagingItems()LazyColumn(verticalArrangement = Arrangement.spacedBy(10.dp),modifier = Modifier.background(grey).fillMaxSize().padding(10.dp)){when(datas.loadState.refresh){is LoadState.Loading-> {item {  loading() }}is LoadState.Error-> {if (datas.itemCount <= 0){item{/*** 全屏显示错误*/failedScreen() {datas.retry()}}}}}itemsIndexed(datas){ _, value ->if (value != null){GithubItem(value)}else{empty {datas.retry()}}}when(datas.loadState.append){is LoadState.NotLoading-> {}is LoadState.Loading-> {item {loading()}}is LoadState.Error-> {if (datas.itemCount > 0){/*** 底部显示加载错误*/item { failed(){datas.retry()} }}}}}
}

相关内容

热门资讯

最新或2023(历届)第三届世... 由国家网信办、科技部、工信部、浙江省政府共同主办的第三届世界互联网大会·互联网之光博览会将于最新或2...
最新或2023(历届)最新无故... 第一篇:无故旷工检讨书  尊敬的领导:  您好~谢谢您能在百忙之中抽空看我写的检讨书!  *月*日,...
汉中之战曹操为何会输?因为他错... 今天趣历史小编为大家带来了一篇关于曹操的文章,欢迎阅读哦~汉献帝被曹操控制后,一直想找机会翻身,可惜...
中秋节招待会上的祝酒词 中秋节... 中秋节招待会上的祝酒词 尊敬的吕梁市政协刘本旺主席,尊敬的柳林县常委贺柱才部长 各位领导...
在迎新茶话会上的发言 迎新茶话... 在迎新茶话会上的发言各位领导、老师们:大家好。很荣幸能有这个会来代表普通教师发言。我在想为什么让我来...