ViewModel、LiveData 使用

ViewModel、LiveData 使用

官方中文教學地址

在看以下內(nèi)容之前,如果對DataBinding不夠熟悉,建議先對DataBinding進行了解。

CSDN:Android DataBinding 使用說明

簡書:Android DataBinding 使用說明

Android DataBinding 使用測試代碼

簡書:ViewModel+LiveData+DataBinding使用

CSDN:ViewModel+LiveData+DataBinding使用

ViewModel 簡介

ViewModel類是用來保存UI數(shù)據(jù)的類,它會在配置變更(即 Configuration Change,例如手機屏幕的旋轉(zhuǎn))之后繼續(xù)存在;我們都知道,當手機屏幕發(fā)生旋轉(zhuǎn)的時候,Activity會被重新創(chuàng)建,也就是說生命周期又將從onCreate開始,如果你此時不及時保存,那么一些UI數(shù)據(jù)將會丟失,這樣肯定是會出問題的。但是,ViewModel并不會受此影響,即便手機屏幕發(fā)生旋轉(zhuǎn),ViewModel依然存在,這樣的話Activity的UI數(shù)據(jù)便可以保存下來。

ViewModel 使用說明、注意

  1. 所有Activity的UI相關(guān)數(shù)據(jù)應(yīng)該保存在ViewModel中,而不是保存在Activity中。這樣做的好處是,在配置變更的時候,你應(yīng)用的UI數(shù)據(jù)仍然存在。即使ViewModel這么強大,但它也不應(yīng)該不承擔過多責任,當有UI數(shù)據(jù)處理等相關(guān)事件建議創(chuàng)建Presenter類,或者創(chuàng)建一個更成熟的架構(gòu)。
  2. Activity負責展示UI數(shù)據(jù),并接收互動(一般來說是與用戶的互動)。但是Activity不應(yīng)當處理這些互動。
  3. 在應(yīng)用需要加載數(shù)據(jù)或者保存數(shù)據(jù)的時候,建議創(chuàng)建一個Repository的存儲區(qū)類,里面放置存儲與加載應(yīng)用數(shù)據(jù)的API。
  4. ViewModel不應(yīng)持有Context,就像之前說的:

    它會在配置變更(即 Configuration Change,例如手機屏幕的旋轉(zhuǎn))之后繼續(xù)存在。

所以,ViewModel生命周期遠比Activity,F(xiàn)ragment等生命周期更長,具體如下圖所示。如果你這樣做了,加入在屏幕旋轉(zhuǎn)情況下,原Activity將會銷毀,新的Activity將會被創(chuàng)建。而ViewModel會一直持有原Activity,這樣便會造成內(nèi)存泄漏。如果你的ViewModel確實需要Context,那么你的ViewModel可以繼承AndroidViewModel,這樣你的ViewModel中會有Application的引用。

  1. ViewModel不應(yīng)當取代onSaveInstanceState方法。盡管ViewModel很出色了,但是它和onSaveInstanceState依然是相輔相成的作用。因為,當進程被關(guān)閉時,ViewModel將會被銷毀,但是onSaveInstanceState不會受到影響。

ViewModel 使用

ViewModel 引入

  1. android.support 形式

     implementation "android.arch.lifecycle:extensions:1.1.1"
     implementation "android.arch.lifecycle:viewmodel:1.1.1"
    
  2. androidx 支持(如下方式引入,包含了ViewModel和LiveData)

     implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
     annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.0.0"
    

ViewModel 用法

  1. 新建數(shù)據(jù)實體類,作為UI需要使用的數(shù)據(jù)

     data class User(var name: String = "", var age: Int = 0, var address: String = "")
    
  2. 新建我的ViewModel類 UserViewModel 繼承至 ViewModel

     class UserViewModel:ViewModel() {
         var user = User("張三",25,"浙江省杭州市")
     }
    
  3. 在Activity/Fragment中實例化

     class MainActivity : AppCompatActivity() {
         override fun onCreate(savedInstanceState: Bundle?) {
             super.onCreate(savedInstanceState)
             setContentView(R.layout.activity_main)
     
             var userViewModel = ViewModelProviders.of(this).get(UserViewModel::class.java)
         }
     }
    

經(jīng)過上面的步驟,我們的ViewModel就算建立好了,現(xiàn)在看上去并沒有什么實際的意義。但是不要急,慢慢的往下看,當他和LiveData以及DataBinding一起使用的時候就會發(fā)現(xiàn)新世界了。

注意點

  1. ViewModel只提供一個默認的無參構(gòu)造函數(shù),如果你需要一個有參構(gòu)造函數(shù),那么就需要使用ViewModelFactory這個類,具體使用方法如下所示:

     // 數(shù)據(jù)實體類
     data class Student(var name: String, var address: String = "")
    
     // ViewModel 類
     class StudentViewModel(var student: Student) : ViewModel()
    
     // 建立 StudentViewModelFactory 類
     class StudentViewModelFactory(private var student: Student) : ViewModelProvider.NewInstanceFactory() {
         override fun <T : ViewModel?> create(modelClass: Class<T>): T {
             return StudentViewModel(student) as T
         }
     }
    
     // 在Activity/Fragment中使用
     class MainActivity : AppCompatActivity() {
         override fun onCreate(savedInstanceState: Bundle?) {
             super.onCreate(savedInstanceState)
             var factory = StudentViewModelFactory(Student("李四","浙江省杭州市"))
             var viewModel = ViewModelProviders.of(this, factory).get(StudentViewModel::class.java)
     }
    

    }

  2. 當我們的 ViewModel 中需要使用Context時,也不應(yīng)該從 Activity/Fragment 中傳遞,而是應(yīng)該讓我們的ViewModel 繼承 AndroidViewModel,這樣就能在 ViewModel 中使用 Application了

     class UserViewModel(application: Application) :AndroidViewModel(application) {
         var user = User("張三",25,"浙江省杭州市")
     }
    

LiveData簡介

LiveData是一個可觀察的數(shù)據(jù)持有者類。與常規(guī)可觀察性不同,LiveData具有生命周期感知能力,這意味著它尊重其他應(yīng)用程序組件(例如Activity、Fragment或Service)的生命周期。這種感知確保LiveData只更新處于活動生命周期狀態(tài)(Observer 的 Lifecycle 對象處于 STARTED 或者 RESUMED 狀態(tài))的應(yīng)用程序組件觀察者。

LiveData 的優(yōu)點

  1. 具有生命周期感知能力,可以做到在組件處于激活狀態(tài)的時候才會回調(diào)相應(yīng)的方法,從而刷新相應(yīng)的 UI。
  2. 不用擔心發(fā)生內(nèi)存泄漏
  3. 當 config 導致 Activity 重新創(chuàng)建的時候,不需要手動取處理數(shù)據(jù)的儲存和恢復(fù)。它已經(jīng)幫我們封裝好了。(需要使用ViewModel)
  4. 當 Actiivty 不是處于激活狀態(tài)的時候,如果你想 Livedata setValue 之后立即回調(diào) obsever 的 onChange 方法,而不是等到 Activity 處于激活狀態(tài)的時候才回調(diào) obsever 的 onChange 方法,你可以使用 ObserveForever 方法,但是你必須在 onDestroy 的時候 removeObserver。

LiveData 使用

LiveData 引入

  1. android.support 形式

     implementation "android.arch.lifecycle:livedata:1.1.1"
    
  2. androidx 支持(如下方式引入,包含了ViewModel和LiveData)

     implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
     annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.0.0"
    

LiveData 基本使用

  1. 直接使用默認值設(shè)置

     // data class
     data class User(var name: String = "", var age: Int = 0, var address: String = "")
    
     // ViewModel 
     class UserViewModel : ViewModel() {
         var userLiveData:MutableLiveData<User> = MutableLiveData()
         init {
             // 初始化是提供默認值
             userLiveData.value = User("張三",25,"浙江省杭州市")
         }
     }
    
     // Activity 
     class MainActivity : AppCompatActivity() {
         override fun onCreate(savedInstanceState: Bundle?) {
             super.onCreate(savedInstanceState)
             setContentView(R.layout.activity_main)
     
             var userViewModel = ViewModelProviders.of(this).get(UserViewModel::class.java)
             text_view.text = userViewModel.userLiveData.value.toString()
         }
     }
    
     // activity_main.xml
     <?xml version="1.0" encoding="utf-8"?>
     <androidx.constraintlayout.widget.ConstraintLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto"
         xmlns:tools="http://schemas.android.com/tools"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         tools:context=".MainActivity">
     
         <Button
             android:id="@+id/bt_change"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:text="修改學生"
             app:layout_constraintTop_toTopOf="parent"/>
     
         <TextView
             android:id="@+id/text_view"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text=""
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintLeft_toLeftOf="parent"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintTop_toTopOf="parent"/>
     
     </androidx.constraintlayout.widget.ConstraintLayout>
    
  2. 點擊事件修改值之后實時更新

     // 只需要在 Activity 的 onCreate() 方法中增加以下代碼即可
    
      // 增加改變監(jiān)聽
     userViewModel.userLiveData.observe(this, Observer {user ->
         text_view.text = user.toString()
     })
     // 點擊按鈕,改變User
     bt_change.setOnClickListener {
         userViewModel.userLiveData.postValue(User("李四",28,"湖南省長沙市"))
     }
    

LiveData 進階使用

  1. map() :把一個數(shù)據(jù)類型變換為另外一個數(shù)據(jù)類型

     // 將 User 對象變?yōu)?String
     private fun map(userLiveData: MutableLiveData<User>): LiveData<String> {
         return Transformations.map(userLiveData) { user ->
             user.name
         }
     }
    
     // 使用
     map(userViewModel.userLiveData).observe(this, Observer {
         text_view.text = it
     })
    
  2. switchMap() : 把一個數(shù)據(jù)變化為另外一個 LiveData

     // 在回調(diào)中創(chuàng)建 LiveData 類型數(shù)據(jù)返回
     private fun switchMap(userLiveData: MutableLiveData<User>): LiveData<String> {
         return Transformations.switchMap(userLiveData) {
             var result = MutableLiveData<String>()
             result.postValue(it.name)
             return@switchMap result
         }
     }
    
     // 使用
     switchMap(userViewModel.userLiveData).observe(this, Observer {
         text_view.text = it
     })
    
  3. MediatorLiveData : LiveData的一個子類,允許合并多個LiveData源。MediatorLiveData對象的觀察者隨后會在任何原始LiveData源對象更改時觸發(fā)

     / data class
     data class User(var name: String = "", var age: Int = 0, var address: String = "")
    
     // Activity 
     class MainActivity : AppCompatActivity() {
         override fun onCreate(savedInstanceState: Bundle?) {
             super.onCreate(savedInstanceState)
             setContentView(R.layout.activity_main)
     
             var userViewModel = ViewModelProviders.of(this).get(UserViewModel::class.java)
    
             var mediatorLiveData: MediatorLiveData<User> = MediatorLiveData()
             var user1 = MutableLiveData<User>()
             var user2 = MutableLiveData<User>()
             mediatorLiveData.addSource(user1) {
                 Log.i("bbb", it.toString())
                 text_view.text = it.address
             }
             mediatorLiveData.addSource(user2) {
                 Log.i("ccc", it.toString())
                 text_view.text = it.address
             }
             // 這一步不能省略
             mediatorLiveData.observe(this, Observer {
                 Log.i("aaa", it.toString())
                 // 此處的返回值好像沒有作用,日志也沒有打印,
                 // 但是該 mediatorLiveData.observe 不能省略,省略的話,界面不能更新
                 text_view.text = it.name
             })
     
             // 點擊按鈕,改變User
             var flag = false
             bt_change.setOnClickListener {
                 if (flag)
                     user1.postValue(User("王五", 26, "深圳"))
                 else
                     user2.postValue(User("趙六", 27, "上海"))
                 flag = !flag
             }
         }
     }
    

MutableLiveData 的 setValue() 和 potValue() 方法

  • setValue():只能在主線程設(shè)置Value
  • postValue():可以在子線程設(shè)置Value

ViewModel+LiveData+DataBinding使用

簡書:ViewModel+LiveData+DataBinding使用
CSDN:ViewModel+LiveData+DataBinding使用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容