孟老板 ListAdapter封装, 告别Adapter代码 (四)
- BaseAdapter系列
- ListAdapter封装, 告别Adapter代码 (一)
- ListAdapter封装, 告别Adapter代码 (二)
- ListAdapter封装, 告别Adapter代码 (三)
- ListAdapter封装, 告别Adapter代码 (四)
- Paging3 系列
ListAdapter封装 (四) - 分页封装;
前言:
这是ListAdapter最后一篇了; 简单封装一下分页逻辑; 由于框架五花八门(网络请求, 下拉刷新, 加载更多等),这篇只做参照即可;
分析:
ViewModel 需要处理: 页码, 请求解析数据, 发送加载更多状态, 发送下拉刷新状态等;
View 需要处理: 初始化Adapter, RecycleView. 绑定加载更多控件, 监听下拉及加载更多状态等;
本篇用到的库:
//loadmore
implementation 'com.github.nukc:loadmorewrapper:1.8.3' //retrofit 2.9 系列
implementation "com.squareup.retrofit2:retrofit:2.9.0" //viewmodel
implementation "androidx.lifecycle:lifecycle-viewmodel:2.2.0"
implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
1.BasePageModel;
它是分页 ViewModel 的基类. 使用 retrofit 拉取数据;
abstract class BasePageModel<T: BaseItem> (application: Application) : AndroidViewModel(application){
private var pageInit = 1
private var page = pageInit
private var pageSize = 10
private var maxPage: Int = 1
/**
* 下拉刷新状态,
*/
var refreshEnabled: MutableLiveData<Boolean> = MutableLiveData(false)
/**
* 加载更多状态
*/
var loadEnabled: MutableLiveData<Boolean> = MutableLiveData(true)
/**
* 列表数据
*/
var listData: MutableLiveData<MutableList<T>> = MutableLiveData(mutableListOf())
fun loadData(param: ArrayMap<String, Any>){
param["page"] = page
param["pageSize"] = pageSize
//发起网络请求.
retrofit<JsonObject>(viewModelScope) {
onSuccess {
disposeResp(it)
}
onFailed { msg, _ ->
Toast.makeText(getApplication(), msg, Toast.LENGTH_SHORT).show()
}
onComplete {
refreshEnabled.value = false
}
api = getResp(ApiManager.INSTANCE.getJsonBody(param))
}
}
/**
* 处理响应;
* 1.解析响应数据; 2.获取总页码数; 3.拼接数据;
* 4.页码++ 5.判断loadMore Enabled 6.取消下拉刷新状态
*/
private fun disposeResp(resp: BaseResp<JsonObject?>){
val list = analysisData(resp.data) ?: mutableListOf()
maxPage = resp.data?.asJsonObject?.get("totalPage")?.asInt ?: 1
if (page == pageInit) {
listData.value = list
} else {
val data = listData.value
data?.addAll(list)
listData.value = data
}
page++
if (page > maxPage) {
switchEnabled(false)
} else {
//数据够,则继续加载; 数据不够了,则关闭加载
switchEnabled(list.size >= pageSize)
}
}
/**
* 切换 loadMore Enabled;
*/
private fun switchEnabled(boolean: Boolean){
if(boolean != loadEnabled.value){
loadEnabled.value = boolean
}
}
/**
* 重新加载数据;
*/
fun reload(){
page = pageInit
listData.value = mutableListOf()
switchEnabled(true)
}
/**
* 处理数据, 因服务器响应数据不规范, 只能用Json接收;
* 可以省去 - 当响应数据可以直接解析为 实体集合时,
*/
abstract fun analysisData(jo: JsonObject?): MutableList<T>?
/**
* retrofit API
*/
abstract suspend fun getResp(rBody: RequestBody): BaseResp<JsonObject?>
}
2. ViewModel
它继承 BasePageModel;
class CheckModel(application: Application) : BasePageModel<CheckEntity>(application) {
override fun analysisData(jo: JsonObject?): MutableList<CheckEntity>? {
val str: String? = jo?.getAsJsonArray("newsList")?.toString()
//将String 解析为 实体集合
return str?.toBeanList()
}
override suspend fun getResp(rBody: RequestBody): BaseResp<JsonObject?> {
return ApiManager.INSTANCE.mApi.getDynamicList(rBody)
}
}
3. MyPageHelper
使用 loadmorewrapper 库 加载更多; 监听数据, 监听状态都写在这个类里
class MyPageHelper(
adapter: BaseAdapter<out BaseItem>,
private val mRecycle: RecyclerView,
private val pageModel: BasePageModel<out BaseItem>,
/**
* Activity 或 Fragment
* 1. 提供 Lifecycle
* 2. 提供 请求参数; 这里全是用 map -> JsonBody 方式提交参数;
*/
private val mView: PagingView
) {
private val mAdapter = adapter as BaseAdapter<BaseItem>
private var mEnabled: LoadMoreAdapter.Enabled? = null fun load(){
LoadMoreWrapper.with(mRecycle.adapter).apply{
setShowNoMoreEnabled(true) // enable show NoMoreView,default false
setListener { enabled: LoadMoreAdapter.Enabled ->
mEnabled = enabled val param = ArrayMap<String, Any>()
mView.prepareMap(param)
pageModel.loadData(param)
}
}.into(mRecycle) // 数据变更时, 刷新列表
pageModel.listData.observe(mView){
mAdapter.submitList(it)
} // 监听没有更多的状态;
// 当页码超出, 或当前页数据不满一页时, 没有更多
// 当页面下拉刷新时,重新启动 loadMore
pageModel.loadEnabled.observe(mView){
setEnabled(it)
}
} /**
* 控制加载更多功能; false: 显示没有更过; true: 滚动到底时触发 loadMore
*/
private fun setEnabled(enabled: Boolean) {
mEnabled?.let {
it.loadMoreEnabled = enabled
if(enabled){
mRecycle.adapter?.notifyItemChanged(mRecycle.adapter?.itemCount ?: 0)
}
}
} /**
* Activity 或 Fragment 需要实现它
*/
interface PagingView : LifecycleOwner {
/**
* 绑定额外请求参数;
*/
fun prepareMap(map: ArrayMap<String, Any>){}
}
}
4.使用
需要实现 MyPageHelper.PagingView; 重写 prepareMap() 提供请求参数
然后初始化 Adapter, RecycleView, Helper;
下拉刷新, 也可以写在 Helper 中;
class CheckPageFragment : BaseMVVMFragment<CheckModel, LayoutRecycleBinding>(),
MyPageHelper.PagingView { private lateinit var mAdapter: SingleChoiceAdapter<CheckEntity>
private var mHelper: MyPageHelper? = null override fun getLayoutId(): Int = R.layout.layout_recycle override fun onLazyLoad() {
//初始化 Adapter 及 RecycleView
mAdapter = SingleChoiceAdapter(R.layout.item_test_choise)
mDataBind.rvRecycle.let {
it.layoutManager = LinearLayoutManager(mActivity)
it.adapter = mAdapter
} //初始化 Helper
mViewModel?.let {
mHelper = MyPageHelper(mAdapter, mDataBind.rvRecycle, it, this)
mHelper?.load()
} //swipeRefresh
mDataBind.swipeRefresh.setOnRefreshListener {
mViewModel?.reload()
}
mViewModel?.refreshEnabled?.observe(this){
mDataBind.swipeRefresh.isRefreshing = it
}
}
}
孟老板 ListAdapter封装, 告别Adapter代码 (四)的更多相关文章
- 孟老板 ListAdapter封装, 告别Adapter代码 (三)
BaseAdapter系列 ListAdapter封装, 告别Adapter代码 (一) ListAdapter封装, 告别Adapter代码 (二) ListAdapter封装, 告别Adapter ...
- 孟老板 ListAdapter封装, 告别Adapter代码 (上)
BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...
- 孟老板 BaseAdapter封装(五) ListAdapter
BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...
- 孟老板 BaseAdapter封装(四) PageHelper
BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...
- 孟老板 BaseAdapter封装 (一) 简单封装
BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...
- 孟老板 BaseAdapter封装 (三) 空数据占位图
BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...
- 孟老板 BaseAdapter封装 (二) Healer,footer
BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...
- 孟老板 Paging3 (二) 结合Room
BaseAdapter系列 ListAdapter系列 Paging3 (一) 入门 Paging3 (二) 结合 Room Paging3 (二) 结合Room Paging 数据源不开放, 无法 ...
- 孟老板 Paging3 (一) 入门
BaseAdapter系列 ListAdapter系列 Paging3 (一) 入门 Paging3 (二) 结合 Room Paging3 (一) 入门 前言: 官方分页工具, 确实香. 但 ...
随机推荐
- Spring Cloud Alibaba(8)---Feign服务调用
Feign服务调用 有关Spring Cloud Alibaba之前写过五篇文章,这篇也是在上面项目的基础上进行开发. Spring Cloud Alibaba(1)---入门篇 Spring Clo ...
- Etcd中Raft日志复制的实现
Raft state of log commitIndex : A log entry is committed once the leader that created the entry has ...
- Educational Codeforces Round 101 (Rated for Div. 2)
A. Regular Bracket Sequence 题意:题目中给(和)还有?,其中?可以转换成为()中的任何一个,并且所给样例中只出现一次(),问能不能括号匹配 思路:直接看第一个和最后一个能不 ...
- [Python] 网络
1.应用概念 应用层(Application Layer):将原始信息进行规范化描述,进而通过标准化接口与传输层对接 传输层(Transport Layer):实现信息的切分和重组,以及应用程序间的对 ...
- [BD] Flume
什么是Flume 采集日志,存在HDFS上 分布式.高可用.高可靠的海量日志采集.聚合和传输系统 支持在日志系统中定制各类数据发送方,用于收集数据 支持对数据进行简单处理,写到数据接收方 组件 sou ...
- HTML中的全局属性
一.全局属性和局部属性 每种元素都有自己规定的属性,这种属性成为局部属性.还有另外一种属性,他可以用来配置所有元素的共有行为,这种属性成为称为全局属性.全局属性可以用在任何一个元素身上,但是不一定会带 ...
- 如何用Python画一个圣诞树呢?
# ./sd.py * *** ***** ******* ********* |[root@bogon shengdan]# vim sd.py[root@bogon shengdan]# cat ...
- shell脚本就是由Shell命令组成的执行文件,将一些命令整合到一个文件中,进行处理业务逻辑,脚本不用编译即可运行。它通过解释器解释运行,所以速度相对来说比较慢。
shell脚本?在说什么是shell脚本之前,先说说什么是shell. shell是外壳的意思,就是操作系统的外壳.我们可以通过shell命令来操作和控制操作系统,比如Linux中的Shell命令就包 ...
- http协议工作原理及工作流程
什么是url ? url = 协议 + 域名 + 资源路径 比如: https://www.baidu.com/index.html http : 超文本传输协议 https: 安全套接字协议 HTT ...
- MyBatis 映射文件详解(六)
MyBatis 配置文件类型 MyBatis配置文件有两种类型,如下: 全局配置文件(如 mybatis-config.xml) Mapper XML 映射文件(如 UserMapper.xml) 上 ...