Android fragment懒加载+分页+上下拉刷新

1,309 阅读3分钟

1.Fragment基类的封装

abstract class BaseFragmentKotlin : Fragment() {
    private var isInitData = false /*标志位 判断数据是否初始化*/
    private var isVisibleToUser = false /*标志位 判断fragment是否可见*/
    private var isPrepareView = false /*标志位 判断view已经加载完成 避免空指针操作*/

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        return inflater.inflate(layoutResId, container, false)
    }

    protected abstract val layoutResId: Int

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        isPrepareView = true
    }

    /*加载数据的方法,由子类实现*/
    abstract fun initData()

    /*懒加载方法,需要在子类的onActivityCreated中调用一次懒加载 避免第一次可见不加载数据*/
    fun lazyInitData() {
        if (!isInitData && isVisibleToUser && isPrepareView) {
            isInitData = true
            initData()
        }
    }

    /*当fragment由可见变为不可见和不可见变为可见时回调*/
    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        this.isVisibleToUser = isVisibleToUser
        lazyInitData()
    }

    protected fun showLoadingDialog(message: String?) {
        LoadingDialog.getInstance().show(context, message)
    }

    protected fun dismissLoadingDialog() {
        LoadingDialog.getInstance().dismiss()
    }

}

2.fragment(布局为SmartRefreshLayout嵌套RecyclerView)

class MessagesFragmentAllnew @SuppressLint("ValidFragment") constructor(//采购,验货,装包
        private val receiveType: Int) : BaseFragmentKotlin() {

    //    1.List只支持读,MutableList才支持写操作  2.it对象变化导致notifyDataSetChanged无效,所以要用本地的locallist
    private var locallist: MutableList<MessageListBean.DataBean.ListBean> = ArrayList()
    private lateinit var viewModel: MessagesViewModelAllnew
    private var mAdapter: MessageAdapternew? = null
    private var pageNum = 1 //页数

    companion object {
        fun newcaogouallInstance() = MessagesFragmentAllnew(receiveType = Constants.CAIGOU)
        fun newyanhouallInstance() = MessagesFragmentAllnew(receiveType = Constants.YANHUO)
        fun newzhuangbaoallInstance() = MessagesFragmentAllnew(receiveType = Constants.ZHUANGBAO)
    }

    override val layoutResId: Int
        get() = R.layout.fragment_read_message

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        recyclerView!!.layoutManager = LinearLayoutManager(context)
        viewModel = ViewModelProviders.of(this).get(MessagesViewModelAllnew::class.java)
        lazyInitData()

//        观察者的生命周期拥有者要写this,不要写viewLifecycleOwner(viewLifecycleOwner在切换间隔2个及以上位置的fragment时,观察者onchange方法会执行2次)
        viewModel.getisLastPage().observe(this, islastpageobserver)
        setRefresh()
    }

    private fun setRefresh() {
        refreshLayout!!.setOnRefreshListener {
            pageNum = 1
            Logger.i("pageNum:$pageNum")
            initData()
        }
        refreshLayout!!.setOnLoadMoreListener {
            Logger.i("pageNum:$pageNum")
            initData()
        }
    }

    override fun initData() {
        showLoadingDialog("")
        viewModel.getneedlistbens(PreUtils.getInstance().getString(context, "tagString", ""), 0,
                receiveType, 2, pageNum).observe(this, listbeansobserver)
        viewModel.getErrormessage().observe(this, errormessageobserver)
    }

    override fun onStart() {
        mAdapter?.let { recyclerView.adapter = it }
        super.onStart()
    }

    private val islastpageobserver: Observer<in Boolean> = Observer {
        refreshLayout.finishRefresh().finishLoadMore()
        if (it == true) {
            refreshLayout.finishLoadMoreWithNoMoreData()
        } else pageNum++
    }

    private val errormessageobserver: Observer<in String> = Observer {
        dismissLoadingDialog()
        refreshLayout.finishRefresh().finishLoadMore()
        toast(it)
    }

    //    观察者使用val或者单独写,这样观察者内部的代码就不会重复执行(匿名内部类会导致内部代码执行多次,即时viewmodel声明为val也会这样)
    //    总结:观察者用成员变量写法,不要使用匿名内部类
    private val listbeansobserver: Observer<MutableList<MessageListBean.DataBean.ListBean>> = Observer {
        dismissLoadingDialog()
//        Logger.i("观察者内部代码执行了几次:needlistbeansobserver")
        if (pageNum == 1) {
            locallist.clear()
            locallist.plusAssign(it)
        } else locallist.plusAssign(it)
        if (mAdapter == null) {
            mAdapter = MessageAdapternew(R.layout.item_read_message_contents, locallist, receiveType)
//                mAdapter!!.setOnItemClickListener { adapter, view, position ->
//                    startActivity<MessageInfoActivity>("data" to locallist[position], "receiveType" to receiveType)
//                }
            recyclerView.adapter = mAdapter
        } else {
            mAdapter!!.notifyDataSetChanged()
        }
    }

}

3.ViewModel使用

class MessagesViewModelAllnew : ViewModel() {
    //    需要的listbens(包含一个listbean集合) 容器需要用val声明
    private val listbens: MutableLiveData<MutableList<MessageListBean.DataBean.ListBean>> by lazy {
        MutableLiveData<MutableList<MessageListBean.DataBean.ListBean>>()
    }
    //        网络异常处理
    private val error_message: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }
    //        是否最后一页
    private val isLastPage: MutableLiveData<Boolean> by lazy {
        MutableLiveData<Boolean>()
    }

    fun getneedlistbens(subarea: String, userId: Int, receiveType: Int,
                        receiveStatus: Int, pageNum: Int): MutableLiveData<MutableList<MessageListBean.DataBean.ListBean>> {
        OkGo.post<MessageListBean>(Constants.HOST_URL + Constants
                .GET_MESSAGE_LIST).params(
                "subarea", subarea).params("receiveType", receiveType).params("userId",
                userId).params("receiveStatus", receiveStatus).params("pageNum", pageNum)
                .execute(object : JsonCallback<MessageListBean>() {
                    override fun onSuccess(response: Response<MessageListBean?>?) {
                        if (response?.body()?.errcode == 0) {
                            listbens.value = response.body()?.data?.list
                            isLastPage.value = response.body()?.data?.isIsLastPage
                        }
                    }

                    override fun onError(response: Response<MessageListBean?>?) {
                        error_message.value = ExceptionHandlekotlin.handleException(response?.exception!!).message
                    }
                })
        return listbens
    }

    fun getErrormessage(): MutableLiveData<String> {
        return error_message
    }

    fun getisLastPage(): MutableLiveData<Boolean> {
        return isLastPage
    }

}

4.注意点

1.List只支持读,MutableList才支持写操作

2.观察者返回的数据对象变化导致notifyDataSetChanged无效,所以用本地的locallist

3.观察者的生命周期拥有者写this,不要写viewLifecycleOwner(viewLifecycleOwner在切换间隔2个及以上位置的fragment时,观察者内部代码会执行2次)

4.观察者用成员变量写法且用val修饰,不要使用匿名内部类(匿名内部类会导致内部代码执行多次,即时viewmodel用val修饰也会这样)

5.LiveData数据容器用val修饰

5.补充

recyclerview适配器中注意else部分代码不能省略

if (item.isRed == 1) {
            helper.getView<View>(R.id.state_tv).setBackgroundColor(mContext.resources.getColor(R.color.red))
        } else {
            helper.getView<View>(R.id.state_tv).setBackgroundColor(mContext.resources.getColor(R.color.white))
        }