本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点
在用DataBinding时要注意DataBinding访问的是静态方法
在kotlin中就要用companion object和@JvmStatic
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参数
fun loadMovie(): Flow<PagingData<Movie>> {return Pager(config = PagingConfig(pageSize = 8,//第一次加载的数量,16也就是2页,默认是3*pageSizeinitialLoadSize = 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 ?: 1val pageSize = params.loadSizeval movies = RetrofitClient.createApi(MoviesApi::class.java).getMovies(currentPage, pageSize)var prevKey: Int? = nullvar nextKey: Int? = null//PagingConfig中的2个参数val realPageSize = 8val initialLoadSize = 16if (currentPage == 1){prevKey = nullnextKey = initialLoadSize / realPageSize + 1}else{prevKey = currentPage - 1nextKey = if (movies.hasMore) currentPage + 1 else null}//下面这样计算,在initialLoadSize不等于realPageSize的时候会有数据错乱//prevKey = if (currentPage == 1) null else currentPage - 1//nextKey = if (movies.hasMore) currentPage + 1 else nullreturn try {LoadResult.Page(data = movies.movieList,prevKey = prevKey,nextKey = nextKey)}catch (e: Exception){e.printStackTrace()return LoadResult.Error(e)}}}
给paging加上拉加载更多
recycleView.adapter = movieAdapter.withLoadStateFooter(MovieLoadMoreAdapter(this@MainActivity))
只需要加个适配器就可以
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.SwipeRefreshLayoutandroid\:id="@+id/swipeRefreshLayout"android\:layout\_width="match\_parent"android\:layout\_height="match\_parent"><androidx.recyclerview.widget.RecyclerViewandroid: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多远时加载数据,默认为pageSizeprefetchDistance = 8),pagingSourceFactory = {MoviePagingSource()}).flow.cachedIn(viewModelScope)}fun loadMovie(): Flow<PagingData<Movie>> = movies}
欢迎关注我的公众号查看更多精彩文章!