孟老板 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 (一) 入门 前言: 官方分页工具, 确实香. 但 ...
随机推荐
- html单页面中用angular js
1.引入angluar js文件 2.html页面应用区域中加入(ng-app="myApp" ng-controller="myController"),区域 ...
- Asp.NetCore Web开发之RazorPage
这节讲一下Razor页面. 首先要明确,Razor 不是一种编程语言.它是服务器端的标记语言,配合C#语言,就可以像PHP语言语言一样(但它们并不相同),处理HTML页面逻辑.它是Asp.NetCor ...
- 教你用SQL实现统计排名
前言: 在某些应用场景中,我们经常会遇到一些排名的问题,比如按成绩或年龄排名.排名也有多种排名方式,如直接排名.分组排名,排名有间隔或排名无间隔等等,这篇文章将总结几种MySQL中常见的排名问题. 创 ...
- X264码率控制总结1——ABR,CQP,CRF
1. X264显式支持的一趟码率控制方法有:ABR, CQP, CRF. 缺省方法是CRF.这三种方式的优先级是ABR > CQP > CRF. if ( bitrate ) rc_me ...
- http://www.loongnix.org/index.php/Lbrowser
http://www.loongnix.org/index.php/Lbrowser 浏览器是桌面应用的核心API软件,龙芯中科早在2011年就开始组建浏览器研发团队开展基于gecko.blink等内 ...
- Linux内存带宽的一些测试笔记
Linux内存带宽的一些测试笔记 首页 所有文章 2014年10月 GNU/Linux系统 2014-10-21 13:20 GNU/LINUX系统 内存带宽 1k 字 669 次 最近要测一下 ...
- linux基础之进阶命令二
本节内容 基础命令二: 1. alias:查看和设置别名(alias:别名) alias 'ren=ls -ld' \ren 可不取消别名,执行ren原本的命令 2. unalia ...
- fprintf函数
描述 C 库函数 int fprintf(FILE *stream, const char *format, ...) 发送格式化输出到流 stream 中. 声明 下面是 fprintf() 函数的 ...
- 【Azure 环境】Azure Key Vault (密钥保管库)中所保管的Keys, Secrets,Certificates是否可以实现数据粒度的权限控制呢?
问题描述 Key Vault (密钥保管库) 能不能针对用户授权实现指定用户只能访问某个或某些特定的key? 如当前有两个用户(User1, User2),在Key Vault中有10个Key,Use ...
- MongoDB(12)- 查询嵌入文档的数组
插入测试数据 db.inventory.insertMany( [ { item: "journal", instock: [ { warehouse: "A" ...