在項目中優雅的使用ViewModel

ViewModel 是jetpack(Google 提供的應用開發框架)中的解耦數據和UI,可感知生命週期的方式存儲數據,可以隨着Activity的生命週期進行數據的控制,解決了以前Activity的切換橫豎屏重新加載數據等問題,但是ViewModel 最主要的不是保存短在的數據在其屬性中,而是通過它進行數據與UI的無感知更新,

一、ViewModel 的生命週期

ViewModel 存在的時間範圍是獲取ViewModel 時傳遞給ViewModelProvider的Lifecycle,而後ViewModel一直會留存在內存中,直到存在時間範圍的Lifecycle永久消失,
在這裏插入圖片描述

上圖對應了到Activity發生屏幕旋轉而結束生命週期的過程中所處的各種狀態,

二、ViewModel使用

class PictureViewModel : ViewModel(){
    val pictureView: MutableLiveData<List<String>> = MutableLiveData()
}
class PictureFragment : Fragment() {
// 1. 申明ViewModel
    private lateinit var viewModel: PictureViewModel
  
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_picture, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 2. 初始化
        viewModel = ViewModelProviders.of(this).get(PictureViewModel::class.java)
        // 3.使用
        viewModel.pictureView.observe(viewLifecycleOwner, Observer { 
            
        })
    }
}

使用其實分上述三步:

  • 聲明對象的類繼承ViewModel
  • 在對應的類中初始化
  • 使用

這個是基本是官方提供的使用方式。但是我們需要給我們的ViewModel 傳遞一個參數,我們怎麼做?

三、在app中統一管理我們的ViewModel

其實上面那個問題官方提供了ViewModelProvider.Factory來解決,我今天就是要通過ViewModelProvider.Factory來集中式的使用ViewModel

涉及類:

  1. InjectorUtils: 單例模式完成給Activity/Fragment提供註冊ViewModel 的方法,實例化請求數據的類,將數據類和ViewModel 進行綁定
  2. PictureRepository ,圖片請求類,完成數據請求或數據庫查詢,其實就是提供獲取數據的
  3. PictureViewModelFactory 繼承ViewModelProvider.Factory :實例化ViewModel

已經描述的很清楚了,看一下具體實現

根據依賴關係,可以倒先寫PictureRepository,在寫ViewModel,接着PictureViewModelFactory,哈哈無所謂啊

// 數據來源
class PictureRepository private constructor(private val context: Context) {


    fun getData() :MutableLiveData<List<String>>{
        // 返回珍視數據
        return MutableLiveData()
    }

    companion object {
        @Volatile
        private var instance: PictureRepository? = null
        fun getInstance(context: Context) = instance ?: synchronized(this) {
            instance ?: PictureRepository(context).also { instance = it }
        }
    }
}
// ViewModewl 傳入PictureRepository,調用獲取數據方法
class PictureViewModel internal constructor(repository: PictureRepository) : ViewModel(){
    val pictureView: MutableLiveData<List<String>> = repository.getData()

}
@Suppress("UNCHECKED_CAST")
class PictureViewModelFactory(private val repository: PictureRepository): ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
    // 傳入PictureRepository
        return PictureViewModel(repository) as T
    }
}
object InjectorUtils {
//提供給Activity/Fragment
    fun providerPictureViewModelFactory(context: Fragment) :PictureViewModelFactory {
        return PictureViewModelFactory(getPictureRepository(context.requireContext()))
    }

    private fun getPictureRepository(context: Context): PictureRepository {
        return PictureRepository.getInstance(context.applicationContext)
    }
}

在Fragment中使用:

class PictureFragment : Fragment() {
    //    private lateinit var viewModel: PictureViewModel
    // 使用
    private val viewModel: PictureViewModel by viewModels {
        InjectorUtils.providerPictureViewModelFactory(this)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_picture, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
//        viewModel = ViewModelProviders.of(this).get(PictureViewModel::class.java)
        viewModel.pictureView.observe(viewLifecycleOwner, Observer {

        })
    }
}

是不是方便很多,
代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章