Android?Hilt?Retrofit?Paging3使用實例
效果視頻
簡述
本Demo采用Hilt+Retrofit+Paging3完成,主要為了演示paging3分頁功能的使用,下列為Demo所需要的相關(guān)依賴
//retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' //paging implementation 'androidx.paging:paging-runtime:3.1.1' implementation 'androidx.paging:paging-compose:1.0.0-alpha14' //Dagger - Hilt implementation("com.google.dagger:hilt-android:2.44") kapt("com.google.dagger:hilt-android-compiler:2.44") // Compose dependencies implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1" implementation "androidx.hilt:hilt-navigation-compose:1.0.0" // Coroutines implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
Hilt+Retrofit
訪問接口
定義需要訪問的接口,此接口是Github api,suspend
字段用于提示后續(xù)引用,此內(nèi)容需要在協(xié)程中使用
interface GithubService { @GET("search/repositories?sort=stars&q=Android") suspend fun queryGithubAsync(@Query("per_page")number:Int, @Query("page") page:Int):DetailsBean }
網(wǎng)絡(luò)實例
提供三個實例,最終外部需要引用的的為UseCase
的實例,具體Hilt
依賴注入此處不予說明,有意者可參考Hilt依賴注入
@Module @InstallIn(SingletonComponent::class) object AppModule { const val BASE_URL:String = "https://api.github.com/" @Singleton @Provides fun providerRetrofit():Retrofit{ return Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build() } @Singleton @Provides fun providerGithubService(retrofit: Retrofit): GithubService { return retrofit.create(GithubService::class.java) } @Singleton @Provides fun providerUseCase(service: GithubService):UseCase{ return UseCase(GetProjects(service)) } }
在Hilt提供的實例中,UseCase
中實現(xiàn)了訪問網(wǎng)絡(luò)接口的任務(wù)
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
我們主要實現(xiàn)load
方法;其中page
為當(dāng)前內(nèi)容頁數(shù),pageSize
為每頁需要加載的內(nèi)容數(shù)量(可在外部進行定義),repository
為獲取的網(wǎng)絡(luò)數(shù)據(jù)實體,previousPage
為前一頁,此處做了一個判斷,如果為第一頁時,則返回null,否則進行滑動至上一頁;nextPage
為下一頁, LoadResult.Page
為分頁加載所需的內(nèi)容; LoadResult.Error
可捕獲異常
class DataPagingSource(private val useCase: UseCase):PagingSource<Int,DetailBean>() { override fun getRefreshKey(state: PagingState<Int, DetailBean>): Int? = null override suspend fun load(params: LoadParams<Int>): LoadResult<Int, DetailBean> { return try { val page = params.key ?: 1 //當(dāng)前頁,默認(rèn)第一頁 val pageSize = params.loadSize //每頁數(shù)據(jù)條數(shù) val repository = useCase.getProjects(page,pageSize) //獲取的數(shù)據(jù)源 val repositoryItem = repository.beans //獲取的數(shù)據(jù)列表 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
在構(gòu)造函數(shù)中調(diào)用Hilt構(gòu)造的實例;其中getData
方法為獲取分頁的數(shù)據(jù),返回為Flow<PagingData<DetailBean>>
類型,其中Flow<PagingData<...>>
外部為固定寫法,內(nèi)部可根據(jù)需要自行定義,然后PagingConfig
的配置中,我們需要配置pageSize
和initialLoadSize
,如果不定義后者,則通過每頁內(nèi)容數(shù)量會是pageSize
的三倍,然后添加我們上述創(chuàng)建的PagingSource
;最后轉(zhuǎn)化為流,然后置于協(xié)程中,它緩存PagingData,以便此流的任何下游集合都將共享相同的數(shù)據(jù)
@HiltViewModel class HomeViewModel @Inject constructor(private val useCase: UseCase):ViewModel() { val PAGE_SIZE = 10 fun getData():Flow<PagingData<DetailBean>>{ return Pager( config = PagingConfig(pageSize = PAGE_SIZE, initialLoadSize = PAGE_SIZE), pagingSourceFactory = { DataPagingSource(useCase) } ).flow.cachedIn(viewModelScope) } }
View
獲取ViewModel中的數(shù)據(jù)
val datas = viewModel.getData().collectAsLazyPagingItems()
同時如果需要添加底部刷新狀態(tài)欄、數(shù)據(jù)錯誤等標(biāo)識,需要監(jiān)聽loadState
,其狀態(tài)總共分為五種:
- refresh:第一次加載數(shù)據(jù)觸發(fā)
- prepend:滑動上一頁觸發(fā)
- append:滑動下一頁觸發(fā)
- source:對應(yīng)于[PagingSource]中的加載
- mediator:對應(yīng)于來自[RemoteMediator]的加載
我們此處主要使用refresh
和append
;
其中,在refresh
中進行監(jiān)聽,如果然后數(shù)據(jù)為null,則顯示全屏錯誤提示,此處為第一次加載數(shù)據(jù);
然后,在append
中監(jiān)聽loading
和Error
兩種狀態(tài),在其loading
是顯示底部加載狀態(tài),在Error
中顯示底部錯誤提示,此處不同于refresh
的Error
狀態(tài),因為有了數(shù)據(jù),就不在需要顯示全屏錯誤提示,在數(shù)據(jù)列表底部顯示錯誤狀態(tài)欄即可
@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()} } } } } } }
到此這篇關(guān)于Android Hilt Retrofit Paging3使用實例的文章就介紹到這了,更多相關(guān)Android Hilt Retrofit Paging3內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android使用RSA加密實現(xiàn)接口調(diào)用時的校驗功能
這篇文章主要介紹了Android+Java使用RSA加密實現(xiàn)接口調(diào)用時的校驗功能,幫助大家更好的利用Android進行開發(fā),感興趣的朋友可以了解下2020-12-12Android中的android:layout_weight使用詳解
layout_weight的作用是設(shè)置子空間在LinearLayout的重要度(控件的大小比重)。layout_weight的值越低,則控件越重要,下面為大家介紹下具體的使用方法2013-06-06Android中Fragment相互切換間不被回收的實現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于Android中Fragment相互切換間不被回收的實現(xiàn)方法,文中給出了詳細的示例代碼和注釋供大家參考學(xué)習(xí),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2017-08-08Android 實現(xiàn)左滑出現(xiàn)刪除選項
滑動刪除的部分主要包含兩個部分, 一個是內(nèi)容區(qū)域(用于放置正常顯示的view),另一個是操作區(qū)域(用于放置刪除按鈕)。下面通過本文給大家介紹Android 實現(xiàn)左滑出現(xiàn)刪除選項,需要的朋友可以參考下2017-06-06AndroidStudio升級4.1坑(無法啟動、插件plugin不好用、代碼不高亮)
這篇文章主要介紹了AndroidStudio升級4.1坑(無法啟動、插件plugin不好用、代碼不高亮),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10