安卓架構組件實戰——ViewModel+LiveData

在谷歌官方提供的安卓架構組件中,有ViewModel、LiveData、Lifecycle、DataBinding等,他們共同組成了一個完整的MVVM架構,實現了視圖與業務邏輯分離,並且提供友好的生命週期管理。本文不會涉及到這些組件的原理解析,百度能找到一堆的我就不重複造輪子了,直接上乾貨教你如何使用。

在使用這些組件之前,我們先來了解下MVVM:

一、MVVM

MVVM即 Model(數據) View(視圖) ViewModel(數據視圖管理器)

具體體現:

Model:bean(實體類)、網絡請求相關、數據庫相關
View:佈局、View、Activity、Fragment 等UI相關
ViewModel:類似於MVP中的Presenter,用於從Model獲取信息,傳遞給View進行顯示,ViewModel與View是綁定在一起的,通過一定手段進行數據交互(例如LiveData)

二、LiveData+ViewModel

LiveData是可觀察的數據持有者類。它具有生命週期感知功能,這意味着它能響應其他應用程序組件(例如Activity、Fragment或Service)的生命週期。這確保LiveData僅更新處於活動的生命週期狀態的應用程序組件觀察者。

在使用LiveData之前,你可以先去了解官方文檔Lifecycle,或者查看我的博客:《安卓架構組件實戰——Lifecycle》

ViewModel:用於Model層和View層數據交互的中間組件,架構組件爲ViewModelUI控制器提供了幫助程序類,該類負責爲UI準備數據。 ViewModel配置更改期間會自動保留對象,以便它們保存的數據可立即用於下一個Activity或Fragment實例。

View和ViewModel通過LiveData來傳遞消息和數據。LiveData是一個可觀察的數據持有者,他可以讓應用程序組件去觀察LiveData中的數據是否發生改變。LiveData還會遵循應用程序組件(Activity,Fragment, Service)的生命週期狀態來避免內存泄露,從而使你的APP不會消費太多的內存(LiveData具備生命週期感知。這意味着除非Activity/fragment是激活狀態(onStart但是還沒有onStop),要不然是不會發起回調的。當fragment調用onStop後, LiveData還會自動刪除觀察者)

LiveData通常和ViewModel一起使用,使用方法如下:

1.引入

//lifecycle
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
//ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-rc02"

非androidx版本:(注意編譯版本28以上,引入的support庫也必須是28.0.0以上的)

// Lifecycle
implementation "android.arch.lifecycle:extensions:1.1.0"
//ViewModel
implementation "android.arch.lifecycle:viewmodel:1.1.0"
//LiveData
implementation "android.arch.lifecycle:livedata:1.1.0"

LiveData 是一個抽象類,它的實現子類有 MutableLiveData ,MediatorLiveData,常用的是 MutableLiveData。

使用如下:

繼承ViewModel即可(kotlin寫法,使用java的童鞋請自行翻譯)

/**
 * 基礎的ViewModel,可以封裝一些通用操作
 *
 */
abstract class BaseViewModel : ViewModel(){
}

LiveData:

class HomeViewModel : BaseViewModel() {
    //定義一個MutableLiveData,設置Value即可
    val data = MutableLiveData<String>()

    fun setData(name: String) {
           //這裏可以去獲取網絡數據,操作數據庫等
          //主線程可以使用setValue() ,異步線程使用postValue()
          data.value = name
    }
}

在Fragment監聽數據變化:

class HomeFragment : BaseFragment() {

    ...省略部分代碼    

    private var homeViewModel: HomeViewModel? = null

    companion object {
        fun newInstance(): HomeFragment {
            return HomeFragment()
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        //獲取ViewModel實例(如果我的ViewModele需要帶參數怎麼辦?看文章後面)
        homeViewModel = ViewModelProviders.of(this)[HomeViewModel::class.java]

        //改變數據
        homeViewModel?.setData("測試")

        //監聽ViewModel裏面的data的數據變化
//        homeViewModel?.data?.observe(this,Observer<String>{data->{
//        } })
        homeViewModel?.data?.observe(this, Observer {
            mProgressDialog?.hide()
            Log.i("test", it)
        })

    }
}

這樣就完成了LiveData和ViewModel的集成,不用我們去關注生命週期的事,簡單明瞭,完整的代碼請看:項目源碼

後記

我們剛剛發現了,在Fragment獲取ViewModel實例是通過如下方式獲取的:

 homeViewModel = ViewModelProviders.of(this)[HomeViewModel::class.java]

這裏它會去執行HomeViewModel的無參構造函數,那麼我的ViewModel構造函數帶參數怎麼辦?

ViewModelProviders.of方法裏面提供了一種方法,傳入一個ViewModelProviders.Factory對象即可,具體寫法:

//構造函數帶參數tips
class MyViewModel(private val tips:String?) :BaseViewModel() {

    val timeData = MutableLiveData<String>()

    init {
        val timer = Timer()

        timer.schedule(object : TimerTask() {
            override fun run() {
                val dataStr = TimeUtil.dateToSecondStr(Date())
                //異步線程使用postValue(),主線程用setValue()/postValue()
                timeData.postValue(tips+dataStr)
            }
        },0,1000)
    }
    
    //構造函數帶參數,需要構建一個Factory,這樣就可以用
    //ViewModelProviders.of(this, MyViewModel.Factory(tips)).get(MyViewModel::class.java)執行帶參數的構造函數
    class Factory(private val tips:String?) : ViewModelProvider.Factory{
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return MyViewModel(tips) as T
        }
    }
}

調用:

myViewModel = ViewModelProviders.of(this, MyViewModel.Factory("當前時間:")).get(MyViewModel::class.java)
        

 

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