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