代码重构之美
随着代码量增多,越来越觉得有必要构建fragment基类,今天实在受不了,于是重构开始…
注入viewmodel
实际上是要真正意义上对viewmodel进行自动注入的,由于我使用的是viewmodelFactory需要传参所以这里没有实现注入
BaseVmFragment.kt
package com.example.module_main.base
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
//虽然没法注入viewmodel但是可以使写法一眼知道碎片对应的ViewModel是什么
abstract class BaseVmFragment<VM: ViewModel>: Fragment() {
//这里的VM并没有实际意义,没有使用到,仅仅用于可观性,让人一眼就知道碎片所对应的viewmodel
lateinit var mActivity: AppCompatActivity
//这个属性用来是否处理 使用jetpack navigation组件导航后,fragment是否重新执行onCreateView方法,重新执行就要重新初始化,之前初始化的状态丢失
abstract var isHandleFragmentAgainOnCreateView: Boolean
protected var isNavigationViewInit = false//记录是否已经初始化过一次视图
protected var lastView: View? = null//记录上次创建的view
//在Fragment直接只用getActivity()获得上下文有时会得到空引用,所以需要重写onAttach方法拿到上下文
override fun onAttach(context: Context) {
super.onAttach(context)
mActivity = activity as AppCompatActivity
onFragmentAttach()
}
/*
* 在fragment 贴附时执行的方法,其实就是onAttach()罢了,只不过我们想要原来的onAttach方法获取上下文对象罢了
* */
abstract fun onFragmentAttach()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(layoutId(),container,false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if(isHandleFragmentAgainOnCreateView){
if(!isNavigationViewInit){
init(savedInstanceState)
isNavigationViewInit = true
}
}else{
init(savedInstanceState)
}
}
fun init(savedInstanceState: Bundle?){
initBeforeBinding(savedInstanceState)
initBinding(savedInstanceState)
initAfterBinding(savedInstanceState)
}
/*
* 可以初始化自己想要的设置
* */
abstract fun initAfterBinding(savedInstanceState: Bundle?)
/*
* 可以初始化如容器转换的设置
* */
abstract fun initBeforeBinding(savedInstanceState: Bundle?)
/*
* 初始化绑定事件
* */
abstract fun initBinding(savedInstanceState: Bundle?)
/*
* 布局资源如R.layout.fragment_test
* */
abstract fun layoutId(): Int
}
注入DataBinding
BaseVmDbFragment.kt
package com.example.module_main.base
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.ViewModel
//自动注入viewmodel和databinding
abstract class BaseVmDbFragment<VM : ViewModel, DB : ViewDataBinding> : BaseVmFragment<VM>() {
private var _binding: DB? = null
val mBinding: DB get() = _binding!!
//这个属性用来是否处理 使用jetpack navigation组件导航后,fragment是否重新执行onCreateView方法,重新执行就要重新初始化,之前初始化的状态丢失
abstract override var isHandleFragmentAgainOnCreateView: Boolean
//注意这里重写方法会直接覆盖BaseVmFragment,因此不用担心BaseVmFragme里onCreateView方法下实现的方法有影响
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
if (isHandleFragmentAgainOnCreateView) {
//通过这种方式解决解决Android jetpack导航组件Navigation返回Fragment重走onCreateView方法刷新视图的问题
if (lastView == null) {
_binding = DataBindingUtil.inflate(inflater, layoutId(), container, false)
//mBinding.lifecycleOwner = this
// 因为这里和数据相关联着,所以这行一定要注释,否则会出现崩溃,这行正确做法应该放到onViewCreated()方法中!!!
lastView = mBinding.root
}
return lastView
} else {
_binding = DataBindingUtil.inflate(inflater, layoutId(), container, false)
mBinding.lifecycleOwner = this
lastView = mBinding.root
return lastView
}
}
override fun onDestroy() {
super.onDestroy()
onFragmentDestroy()
_binding = null
}
//- - - 注意以下两个方法除非是特殊需要否则直接覆盖后不执行操作即可!!!之所以把方法暴露出来是为了防止有特殊需求 ^.^
/*
* 在fragment销毁时执行的方法,其实就是onDestroy()罢了,只不过我们想要原来的onDestory()方法执行_binding = null操作而已
* */
abstract fun onFragmentDestroy()
/*
* 在fragment 贴附时执行的方法,其实就是onAttach()罢了,只不过我们想要原来的onAttach方法获取上下文对象罢了
* */
abstract override fun onFragmentAttach()
}
fragment基类的创建
BaseFragment.kt
package com.example.module_main.base
import android.os.Bundle
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.ViewModel
//创建这个类没有实际作用,主要就是为了看起来好看,暴露所有需要或者重要的方法给使用者看, 老强迫症了
abstract class BaseFragment<VM: ViewModel, DB: ViewDataBinding>: BaseVmDbFragment<VM, DB>(){
//- - - 注意以下onFragmentDestroy和onFragmentAttach两个方法通常覆盖后不操作!!! 之所以把方法暴露出来是为了防止有特殊需求 ^.^
//- - - layoutId方法必须覆盖!!!
/*
* 这个属性用来是否处理 使用jetpack navigation组件导航后,fragment是否重新执行onCreateView方法,重新执行就要重新初始化,之前初始化的状态丢失
* 为false表示不处理fragment重新初始化
* 为true表示处理fragment重新初始化
* */
abstract override var isHandleFragmentAgainOnCreateView: Boolean
/*
* 在fragment销毁时执行的方法,其实就是onDestroy()罢了,只不过我们想要原来的onDestory()方法执行_binding = null操作而已
* 在onDestory()方法内执行
* */
abstract override fun onFragmentDestroy()
/*
* 在fragment 贴附时执行的方法,其实就是onAttach()罢了,只不过我们想要原来的onAttach方法获取上下文对象罢了
* 在onAttach()方法内执行
* */
abstract override fun onFragmentAttach()
/**
* 当前Fragment绑定的视图布局
*/
abstract override fun layoutId(): Int
/**
* Fragment执行onViewCreated后触发,可以初始化如容器转换的设置,如果没有容器转换或fragment的进出动画要设置可以不初始化这个方法内容
* 在initBinding方法前调用
*/
abstract override fun initBeforeBinding(savedInstanceState: Bundle?)
/*
* 初始化绑定事件
* */
abstract override fun initBinding(savedInstanceState: Bundle?)
/*
* 初始化除了绑定操作外用户想自己定义的内容
* 在initBinding方法后调用
* */
abstract override fun initAfterBinding(savedInstanceState: Bundle?)
}