孟老板 ListAdapter封装, 告别Adapter代码 (四)

 

 

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
        }
    }
}

 

回到顶部

posted @ 2021-06-16 11:04  孟老板  阅读(228)  评论(0编辑  收藏  举报