孟老板 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 (一) 入门 前言: 官方分页工具, 确实香. 但 ...
随机推荐
- 多变量高斯(MVN)概率建模的两种方案
摘要:在我们的时序异常检测应用中,设计了对时序数据进行多变量高斯(MVN)建模的算法方案进行异常检测,本文对基于tensorflow的两种MVN建模方案进行了总结. 1.基于custom choles ...
- Base64文件上传(Use C#)
Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,它是一种基于64个可打印字符来表示二进制数据的方法. 使用base64进行文件上传的具体流程是:前台使用js将文件转换为base64格 ...
- Ubuntu切换到root账户
使用命令sudo su或sudo -i然后输入密码就可以切换到root帐号,exit可以退出.
- 在C++中调用Python
技术背景 虽然现在Python编程语言十分的火爆,但是实际上非要用一门语言去完成所有的任务,并不是说不可以,而是不合适.在一些特定的.对于性能要求比较高的场景,还是需要用到传统的C++来进行编程的.但 ...
- Vim删除空行
Vim删除空行 1 Vim删除空行 打开vim输入:g/^$/d :g将在与正则表达式匹配的行上执行命令. 正则表达式是'空行',命令是:d (删除)
- Linux 如何查看系统负载
Linux 如何查看系统负载 310 博客 / Linux/ 4个月前/ 534 / 0 操作系统的负载状态,反映了应用程序的资源使用情况,从中能找出应用程序优化的瓶颈所在. 系统平均负载, ...
- Scala 关键字
Java关键字 Java 一共有 50 个关键字(keywords),其中有 2 个是保留字,目前还不曾用到:goto 和 const.true.false 和 null 看起来很像关键字,但实际上只 ...
- Linux进阶之LAMP和LNMP动态网站搭建
一.什么是LAMP LAMP=Linux Apache Mysql/MariaDB PHP/Perl/Python 这些软件都是开源免费的软件,几个程序各自是独立的,经常为了达到我们需要的效果而协同工 ...
- Java public 和 private 访问修饰符
何为封装 从事面向对象编程的 Java 程序员,不可能不知道封装,它是面向对象编程的精髓,非常重要. 那什么是封装?字面意思就是把摆在外面的东西包起来. 一句话,封装就是对外隐藏内部细节. 那为何要封 ...
- JavaEE 学大数据是否掌握 JavaSE 和 Linux 就够了?
引言 如果你是学习大数据的童靴,可能经常在网上看到一些公众号或博客告诉你,学习大数据基础部分只需要掌握 JavaSE 和 Linux 就够了,至于 JavaWeb 和 JavaEE 简单了解一下就可以 ...