前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kotlin Jetpack Paging3 和Flow结合使用注意点

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

作者头像
AntDream
发布2024-06-13 21:06:14
670
发布2024-06-13 21:06:14
举报

在用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
代码语言:javascript
复制
<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>
  • 加上刷新监听
代码语言:javascript
复制
swipeRefreshLayout.setOnRefreshListener {
	movieAdapter.refresh()
}

  • 监听刷新结束
代码语言:javascript
复制
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保持一致
代码语言:javascript
复制
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

}

码字不易,求转发,求点在看,求关注,感谢!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AntDream 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 在用DataBinding时要注意DataBinding访问的是静态方法
  • Paging3分页数据错乱的问题
  • 给Paging加上拉加载更多
  • Paging加上下拉刷新
  • 下拉刷新后,底部上拉加载更多的loadmore的动画不显示
  • APP横竖屏切换之后paging加载的数据没有缓存起来
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档