在用DataBinding时要注意DataBinding访问的是静态方法
在Kotlin中就要用companion object和@JvmStatic
代码语言:javascript复制class ImageViewBindingAdapter {
//里面的BindingAdapter方法必须是静态方法,否则会编译会报错
//DataBinding调用必须是静态方法
companion object {
@JvmStatic
@BindingAdapter("image")
fun setImage(imageView:ImageView, url: String){
if (!TextUtils.isEmpty(url)){
//加载网络图片
} else{
imageView.setBackgroundColor(Color.GRAY)
}
}
}
}
Paging3分页数据错乱的问题
在计算paging的prevKey和nextKey,也就是上一页,下一页的时候,需要考虑PagingConfig中的initialLoadSize参数
代码语言:javascript复制fun loadMovie(): Flow<PagingData<Movie>> {
return Pager(
config = PagingConfig(
pageSize = 8,
//第一次加载的数量,16也就是2页,默认是3*pageSize
initialLoadSize = 16
),
pagingSourceFactory = { MoviePagingSource() }
).flow
}
class MoviePagingSource: PagingSource<Int, Movie>() {
override fun getRefreshKey(state: PagingState<Int, Movie>): Int? {
//第一次加载
return 1
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Movie> {
val currentPage = params.key ?: 1
val pageSize = params.loadSize
val movies = RetrofitClient.createApi(MoviesApi::class.java).getMovies(currentPage, pageSize)
var prevKey: Int? = null
var nextKey: Int? = null
//PagingConfig中的2个参数
val realPageSize = 8
val initialLoadSize = 16
if (currentPage == 1){
prevKey = null
nextKey = initialLoadSize / realPageSize 1
}else{
prevKey = currentPage - 1
nextKey = if (movies.hasMore) currentPage 1 else null
}
//下面这样计算,在initialLoadSize不等于realPageSize的时候会有数据错乱
//prevKey = if (currentPage == 1) null else currentPage - 1
//nextKey = if (movies.hasMore) currentPage 1 else null
return try {
LoadResult.Page(
data = movies.movieList,
prevKey = prevKey,
nextKey = nextKey
)
}catch (e: Exception){
e.printStackTrace()
return LoadResult.Error(e)
}
}
}
给Paging加上拉加载更多
代码语言:javascript复制recycleView.adapter = movieAdapter.withLoadStateFooter(MovieLoadMoreAdapter(this@MainActivity))
只需要加个适配器就可以
代码语言:javascript复制class MovieLoadMoreAdapter(private val context: Context): LoadStateAdapter<BindViewHolder>() {
override fun onBindViewHolder(holder: BindViewHolder, loadState: LoadState) {
}
override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): BindViewHolder {
val binding = MovieLoadmoreBinding.inflate(LayoutInflater.from(context), null, false)
return BindViewHolder(binding)
}
}
Paging加上下拉刷新
- 布局加上SwipeRefreshLayout
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@ id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@ id/recycleView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
- 加上刷新监听
swipeRefreshLayout.setOnRefreshListener {
movieAdapter.refresh()
}
- 监听刷新结束
lifecycleScope.launchWhenCreated {
movieAdapter.loadStateFlow.collectLatest { state ->
mBinding.swipeRefreshLayout.isRefreshing = state.refresh is LoadState.Loading
}
}
下拉刷新后,底部上拉加载更多的loadmore的动画不显示
- PageConfig还有一个属性是prefetchDistance,预刷新的距离,距离最后一个item多远时加载数据,默认为pageSize
- 当prefetchDistance很小,并且initialLoadSize也很小时,就会出现上面的bug。比如initialLoadSize=8,prefetchDistance=1时
- 解决办法也比较简单,2个属性设置的大一点就行了
APP横竖屏切换之后paging加载的数据没有缓存起来
- ViewModel缓存数据要在属性中
- 还有就是Paging返回的是flow,需要用cachedIn(viewModelScope)来让Paging的flow的生命周期和ViewModelScope的生命周期保持一致,也就是和activity保持一致
class MovieViewModel: ViewModel() {
private val movies by lazy {
Pager(
config = PagingConfig(
pageSize = 8,
//第一次加载的数量,16也就是2页
initialLoadSize = 16,
//预刷新的距离,距离最后一个item多远时加载数据,默认为pageSize
prefetchDistance = 8
),
pagingSourceFactory = { MoviePagingSource() }
).flow.cachedIn(viewModelScope)
}
fun loadMovie(): Flow<PagingData<Movie>> = movies
}
码字不易,求转发,求点在看,求关注,感谢!