孟老板 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 } } }