1 Star 71 Fork 32

John-逍遥 / android_plugin_readme

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README_paging3.md 12.43 KB
一键复制 编辑 原始数据 按行查看 历史
John-逍遥 提交于 2021-11-21 01:22 . 新增readme

Paging3 实现分页 代码展示

以下只展示关键部分

gradle 依赖引用

dependencies {
   ...
    // Paging 3.0
    implementation 'androidx.paging:paging-runtime:3.0.0-beta01'
	// 下拉刷新组件
    implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
    // RecyclerView
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
	...
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">    

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recyclerview"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>

            <ProgressBar
                android:id="@+id/progress_bar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center" />
        </FrameLayout>
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>
MainActivity.kt
package com.lujianfei.plugin1_15

import android.content.Intent
import android.net.Uri
import android.view.View
import android.widget.ProgressBar
import android.widget.Toast
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.paging.LoadState
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.lujianfei.module_plugin_base.base.BasePluginActivity
import com.lujianfei.module_plugin_base.beans.PluginActivityBean
import com.lujianfei.module_plugin_base.widget.PluginToolBar
import com.lujianfei.plugin1_15.adapter.FooterAdapter
import com.lujianfei.plugin1_15.adapter.MainAdapter
import com.lujianfei.plugin1_15.viewmodel.MainViewModel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch


class MainActivity : BasePluginActivity() {
    companion object {
        const val TAG = "MainActivity"
    }   
    private var recyclerview:RecyclerView ?= null
    private var progress_bar:ProgressBar ?= null
    private var swipeRefreshLayout:SwipeRefreshLayout ?= null
    private val mAdapter by lazy { MainAdapter() }
    private var mMainViewModel: MainViewModel?= null

    override fun resouceId(): Int = R.layout.activity_main
    
    override fun initView() {       
        swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout)
        progress_bar = findViewById(R.id.progress_bar)
        recyclerview = findViewById(R.id.recyclerview)
        recyclerview?.apply {
            layoutManager = LinearLayoutManager(that)
            addItemDecoration(DividerItemDecoration(that, DividerItemDecoration.VERTICAL))
            adapter = mAdapter.withLoadStateFooter(
                footer = FooterAdapter {
                mAdapter.retry()
            })
        }
        mMainViewModel = that?.let { ViewModelProvider(it).get(MainViewModel::class.java) }
        swipeRefreshLayout?.isEnabled = false
    }

    override fun initData() {       
        that?.let {
            mMainViewModel?.viewModelScope?.launch {
                // 绑定数据
                mMainViewModel?.getPagingData()?.collect { pagingData->
                    mAdapter.submitData(pagingData)
                }
            }
        }
    }

    override fun initEvent() {     
        mAdapter.addLoadStateListener {
            when (it.refresh) {
                // 加载完毕
                is LoadState.NotLoading -> {
                    // 下载组件激活
                    swipeRefreshLayout?.isEnabled = true
                    // 收起下拉刷新
                    swipeRefreshLayout?.isRefreshing = false

                    // 隐藏中间加载提示,显示列表
                    progress_bar?.visibility = View.INVISIBLE
                    recyclerview?.visibility = View.VISIBLE
                }
                // 加载中
                is LoadState.Loading -> {
                    if (mAdapter.itemCount == 0) { // 空数据时
                        // 显示中间加载提示
                        progress_bar?.visibility = View.VISIBLE
                        recyclerview?.visibility = View.INVISIBLE
                    }
                }
                // 加载失败
                is LoadState.Error -> {
                    // 收起下拉刷新
                    swipeRefreshLayout?.isRefreshing = false
                    val state = it.refresh as LoadState.Error
                    progress_bar?.visibility = View.INVISIBLE
                    Toast.makeText(that, "Load Error: ${state.error.message}", Toast.LENGTH_SHORT).show()
                }
            }
        }
        swipeRefreshLayout?.setOnRefreshListener {
            mAdapter.refresh()
        }
    }
}
MainAdapter.kt
package com.lujianfei.plugin1_15.adapter

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.lujianfei.plugin1_15.R
import com.lujianfei.plugin1_15.model.MainBean

/**
 * 我们可以理解为RecycleView.Adapter,实际上它也是实现的RecyclerView.Adapter。
 * 这个方法中有 submit() 方法非常重要,这个方法是开启数据加载的最后一环,所以必须实现。
 * 其中这个 adapter 中还包含 refresh() 和 retry() 的方法,顾名思义刷新和重试,
 * 还有就是adapter.loadStateFlow的监听,用于监听数据加载的状态
 */
class MainAdapter : PagingDataAdapter<MainBean,RecyclerView.ViewHolder>(COMPARATOR) {

    companion object {
        private val COMPARATOR = object : DiffUtil.ItemCallback<MainBean>() {
            override fun areItemsTheSame(oldItem: MainBean, newItem: MainBean): Boolean {
                return oldItem.id == newItem.id
            }

            override fun areContentsTheSame(oldItem: MainBean, newItem: MainBean): Boolean {
                return oldItem == newItem
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.adapter_main, parent, false))
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        if (holder is MyViewHolder) {
            holder.setData(getItem(position))
        }
    }

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        var title: TextView? = null
        var summary: TextView? = null

        init {
            title = itemView.findViewById(R.id.title)
            summary = itemView.findViewById(R.id.summary)
        }

        fun setData(mainBean: MainBean?) {
            title?.text = mainBean?.title
            summary?.text = mainBean?.summary
        }
    }
}
MainBean.kt
package com.lujianfei.plugin1_15.model

data class MainBean(
        var id:Int,
        var title: String,
        var summary: String
)
MainViewModel.kt
package com.lujianfei.plugin1_15.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.cachedIn
import com.lujianfei.plugin1_15.data.MainRepository
import com.lujianfei.plugin1_15.model.MainBean
import kotlinx.coroutines.flow.Flow

class MainViewModel: ViewModel() {

    fun getPagingData(): Flow<PagingData<MainBean>> {
        return MainRepository.getPagingData().cachedIn(viewModelScope)
    }
}
MainPagingSource.kt
package com.lujianfei.plugin1_15.data

import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.lujianfei.plugin1_15.model.MainBean
import kotlinx.coroutines.delay

/**
 * MainPagingSource
 * 主要承担的就是数据的获取,可以理解为,
 * 我们的网络请求或者读取本地数据库的数据
 */
class MainPagingSource: PagingSource<Int,MainBean>() {

    override fun getRefreshKey(state: PagingState<Int, MainBean>): Int?  = null

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MainBean> {
        val page = params.key ?: 1 // set page 1 as default
        val pageSize = params.loadSize
        val items = getData(page)
        val prevKey = if (page > 1) page - 1 else null
        val nextKey = if (items.isNotEmpty()) page + 1 else null
        return LoadResult.Page(items, prevKey, nextKey)
    }

    private suspend fun getData(page:Int = 1):List<MainBean> {
        delay(2000L)
        val mData = arrayListOf<MainBean>()
        when (page) {
            1 -> {
                for (idx in 0 until 20) {
                    mData.add(
                        MainBean(id = idx,title = "码农宝标题 $idx", summary = "码农宝简介:主要功能:\n" +
                                "- 快速查看安卓设备信息 (手机屏幕分辨率,手机型号,设备id, 可用内存等等)\n" +
                                "- 各类开发过程中常用代码及效果 Demo, 分别有\n" +
                                "- 列表, 容器,对话框,动画,翻页,图表,编码及算法,多媒体,传感器,实用工具等 $idx")
                    )
                }
            }
            2 -> {
                for (idx in 20 until 40) {
                    mData.add(
                        MainBean(id = idx,title = "码农宝标题 $idx", summary = "码农宝简介:主要功能:\n" +
                                "- 快速查看安卓设备信息 (手机屏幕分辨率,手机型号,设备id, 可用内存等等)\n" +
                                "- 各类开发过程中常用代码及效果 Demo, 分别有\n" +
                                "- 列表, 容器,对话框,动画,翻页,图表,编码及算法,多媒体,传感器,实用工具等 $idx")
                    )
                }
            }
        }
        return mData
    }
}
MainRepository.kt
package com.lujianfei.plugin1_15.data

import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.lujianfei.plugin1_15.model.MainBean
import kotlinx.coroutines.flow.Flow

object MainRepository {

    private const val PAGE_SIZE = 20

    fun getPagingData(): Flow<PagingData<MainBean>> {
        return Pager(
            config = PagingConfig(PAGE_SIZE),
            pagingSourceFactory = { MainPagingSource() }
        ).flow
    }
}
FooterAdapter.kt
package com.lujianfei.plugin1_15.adapter

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ProgressBar
import androidx.core.view.isVisible
import androidx.paging.LoadState
import androidx.paging.LoadStateAdapter
import androidx.recyclerview.widget.RecyclerView
import com.lujianfei.plugin1_15.R

/**
 * 加载更多的 Footer
 */
class FooterAdapter(val retry: () -> Unit) : LoadStateAdapter<FooterAdapter.ViewHolder>() {

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val progressBar: ProgressBar = itemView.findViewById(R.id.progress_bar)
        val retryButton: Button = itemView.findViewById(R.id.retry_button)
    }

    override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.footer_item, parent, false)
        val holder = ViewHolder(view)
        holder.retryButton.setOnClickListener {
            retry()
        }
        return holder
    }

    override fun onBindViewHolder(holder: ViewHolder, loadState: LoadState) {
        holder.progressBar.isVisible = loadState is LoadState.Loading
        holder.retryButton.isVisible = loadState is LoadState.Error
    }
}
Android
1
https://gitee.com/lujianfei/android_plugin_readme.git
git@gitee.com:lujianfei/android_plugin_readme.git
lujianfei
android_plugin_readme
android_plugin_readme
master

搜索帮助