Kotlin Jetpack Paging3 和Flow结合使用注意点

36 篇文章 0 订阅

本文首发于公众号“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*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加上拉加载更多

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.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

}

欢迎关注我的公众号查看更多精彩文章!

AntDream

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值