代碼重構之美
隨著代碼量增多,越來越覺得有必要構建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?)
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/321300.html
標籤:其他
