“This is the seventh day of my participation in the First Challenge 2022. For details: First Challenge 2022
Add the dependent
implementation "Androidx. The paging: the paging - runtime: 3.0.0 - beta02"
implementation "Androidx. The paging: the paging - compose: 1.0.0 - alpha08"
Copy the code
The way retrofit2 is used is described here, and I’ll try to make it as simple as possible. The process for Retrofit2 is
Initialize Retrofit to create a globally available Retrofit object, typically a singleton pattern writing request interface to build a repository
❤️Android OkHttp+Retrofit+Rxjava+Hilt implementation of the Network request framework ❤️
Get back to business
The use of Paging3
paging.pager
Primary entry point into Paging; constructor for a reactive stream of PagingData. Translation is the main entry point for paging; Constructor of the reaction flow for paging data.
This is what this guy looks like
public class Pager<Key : Any, Value : Any>
// propagate to the public API with constructor arguments.
@ExperimentalPagingApi constructor(
config: PagingConfig,
initialKey: Key? = null, remoteMediator: RemoteMediator<Key, Value>? , pagingSourceFactory: () -> PagingSource<Key, Value> )Copy the code
There are four parameters
PagingConfig
First, PagingConfig has five configurations
PagingConfig parameters | The default value |
---|---|
pageSize: Int | There is no |
prefetchDistance: Int | pageSize |
enablePlaceholders: Boolean | true |
initialLoadSize: Int | pageSize * 3 |
maxSize: Int | infinite |
PagingConfig: Object used to configure the loading behavior within the pager when loading content from a paging source
Defines the number of items loaded from PagingSource at one time.
pageSize
It should be several times the number of items visible on the screen. Note: pageSize is used to inform PagingSource. Load parameters. LoadSize, but not enforced. PagingSource may ignore this value entirely and still return a valid page.
prefetchDistance
PrefetchDistance defaults to = pageSize defines whether paging data can display empty placeholders if the paging source provides them.
PagingData will display an empty placeholder for content that has not been loaded if the following two conditions are met: 1. Its PagingSource can count all unloaded items (to know the number of empty values to display). 2. Enableplaceholder is set to True
enablePlaceholders
Define the load size of the request for the initial load of the PagingSource, usually greater than the pageSize, so that when the data is first loaded, the range of content loaded is large enough to cover a small scrollbar.
Note: initialLoadSize is used to inform PagingSource. Load parameters. LoadSize, but not enforced. PagingSource may ignore this value entirely, but still return a valid initial page
initialLoadSize
Defines the maximum number of items that can be loaded into PagingData before a page is deleted.
maxSize
The maximum?
initialKey
Create a new entity to hold the PagingConfig configuration
data class AppPagingConfig
Copy the code
PagingSource
We use Pager’s config and initialKey
The load and getRefreshKey methods are overridden for further encapsulation
config: AppPagingConfig = AppPagingConfig()
initialKey: K? = null. Pager( config = baseConfig, initialKey = initialKey ) {object : PagingSource<K, V>() {
override suspend fun load(params: LoadParams<K>): LoadResult<K, V> {
return loadData.invoke(params)
}
override fun getRefreshKey(state: PagingState<K, V>): K? {
return initialKey
}
}
}.flow.cachedIn(viewModelScope)
Copy the code
loadData: suspend (PagingSource.LoadParams<K>) -> PagingSource.LoadResult<K, V>
Copy the code
The logic that makes a network request in loadData returns loadResult. Page on success and loadResult. Error on failure
The complete code
fun <T : Any> ViewModel.simplePager(
config: AppPagingConfig = AppPagingConfig(),
callAction: suspend (page: Int) -> BasicBean<ListWrapper<T>>
): Flow<PagingData<T>> {
return pager(config, 0) {
valpage = it.key ? :0
val response = try {
// The requested data
HttpResult.Success(callAction.invoke(page))
} catch (e: Exception) {
HttpResult.Error(e)
}
when (response) {
is HttpResult.Success -> {
val data = response.result.data
val hasNotNext = (data!!!!! .datas.size < it.loadSize) && (data.over)
// loadresult. Page for details, see the previous article
//data= Requested data content
PagingSource.LoadResult.Page(
data = response.result.data!!!!! .datas, prevKey =if (page - 1 > 0) page - 1 else null,
nextKey = if (hasNotNext) null else page + 1)}is HttpResult.Error -> {
PagingSource.LoadResult.Error(response.exception)
}
}
}
}
fun <K : Any, V : Any> ViewModel.pager(
config: AppPagingConfig = AppPagingConfig(),
initialKey: K? = null,
loadData: suspend (PagingSource.LoadParams<K>) -> PagingSource.LoadResult<K, V>
): Flow<PagingData<V>> {
val baseConfig = PagingConfig(
config.pageSize,
initialLoadSize = config.initialLoadSize,
prefetchDistance = config.prefetchDistance,
maxSize = config.maxSize,
enablePlaceholders = config.enablePlaceholders
)
return Pager(
config = baseConfig,
initialKey = initialKey
) {
object : PagingSource<K, V>() {
override suspend fun load(params: LoadParams<K>): LoadResult<K, V> {
return loadData.invoke(params)
}
override fun getRefreshKey(state: PagingState<K, V>): K? {
return initialKey
}
}
}.flow.cachedIn(viewModelScope)
}
Copy the code
data class AppPagingConfig(
val pageSize: Int = 20.val initialLoadSize: Int = 20.val prefetchDistance:Int = 1.val maxSize:Int = PagingConfig.MAX_SIZE_UNBOUNDED,
val enablePlaceholders:Boolean = false
)
Copy the code
Method of use
Configure paging data in the ViewModel to convert data to flow using flow and cachedIn(viewModelScope) to cache data in the ViewModel
private val pager by lazy {
simplePager {
//it = number of pages loaded
// Request data based on page number
service.getSquareData(it)
}.cachedIn(viewModelScope)
}
var viewStates by mutableStateOf(ViewState(pagingData = pager))
private set
data class ViewState(
val pagingData: PagingBean
)
typealiasPagingBean = Flow<PagingData< Entity class >>Copy the code
To render the UI
val viewStates = remember { viewModel.viewStates }
val squareData = viewStates.pagingData.collectAsLazyPagingItems()
LazyColumn() {
itemsIndexed(squareData) { _, item ->
Text(text = item.data)}}Copy the code
The next post is used with the SwipeRefresh drop-down refresh