ViewModel、LiveData 使用
在看以下内容之前,如果对DataBinding不够熟悉,建议先对DataBinding进行了解。
简书:ViewModel+LiveData+DataBinding使用
CSDN:ViewModel+LiveData+DataBinding使用
ViewModel 简介
ViewModel类是用来保存UI数据的类,它会在配置变更(即 Configuration Change,例如手机屏幕的旋转)之后继续存在;我们都知道,当手机屏幕发生旋转的时候,Activity会被重新创建,也就是说生命周期又将从onCreate开始,如果你此时不及时保存,那么一些UI数据将会丢失,这样肯定是会出问题的。但是,ViewModel并不会受此影响,即便手机屏幕发生旋转,ViewModel依然存在,这样的话Activity的UI数据便可以保存下来。
ViewModel 使用说明、注意
- 所有Activity的UI相关数据应该保存在ViewModel中,而不是保存在Activity中。这样做的好处是,在配置变更的时候,你应用的UI数据仍然存在。即使ViewModel这么强大,但它也不应该不承担过多责任,当有UI数据处理等相关事件建议创建Presenter类,或者创建一个更成熟的架构。
- Activity负责展示UI数据,并接收互动(一般来说是与用户的互动)。但是Activity不应当处理这些互动。
- 在应用需要加载数据或者保存数据的时候,建议创建一个Repository的存储区类,里面放置存储与加载应用数据的API。
- ViewModel不应持有Context,就像之前说的:
它会在配置变更(即 Configuration Change,例如手机屏幕的旋转)之后继续存在。
所以,ViewModel生命周期远比Activity,Fragment等生命周期更长,具体如下图所示。如果你这样做了,加入在屏幕旋转情况下,原Activity将会销毁,新的Activity将会被创建。而ViewModel会一直持有原Activity,这样便会造成内存泄漏。如果你的ViewModel确实需要Context,那么你的ViewModel可以继承AndroidViewModel,这样你的ViewModel中会有Application的引用。
- ViewModel不应当取代onSaveInstanceState方法。尽管ViewModel很出色了,但是它和onSaveInstanceState依然是相辅相成的作用。因为,当进程被关闭时,ViewModel将会被销毁,但是onSaveInstanceState不会受到影响。
ViewModel 使用
ViewModel 引入
-
android.support 形式
implementation "android.arch.lifecycle:extensions:1.1.1" implementation "android.arch.lifecycle:viewmodel:1.1.1"
-
androidx 支持(如下方式引入,包含了ViewModel和LiveData)
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0" annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.0.0"
ViewModel 用法
-
新建数据实体类,作为UI需要使用的数据
data class User(var name: String = "", var age: Int = 0, var address: String = "")
-
新建我的ViewModel类 UserViewModel 继承至 ViewModel
class UserViewModel:ViewModel() { var user = User("张三",25,"浙江省杭州市") }
-
在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) } }
经过上面的步骤,我们的ViewModel就算建立好了,现在看上去并没有什么实际的意义。但是不要急,慢慢的往下看,当他和LiveData以及DataBinding一起使用的时候就会发现新世界了。
注意点
-
ViewModel只提供一个默认的无参构造函数,如果你需要一个有参构造函数,那么就需要使用ViewModelFactory这个类,具体使用方法如下所示:
// 数据实体类 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) }
}
-
当我们的 ViewModel 中需要使用Context时,也不应该从 Activity/Fragment 中传递,而是应该让我们的ViewModel 继承 AndroidViewModel,这样就能在 ViewModel 中使用 Application了
class UserViewModel(application: Application) :AndroidViewModel(application) { var user = User("张三",25,"浙江省杭州市") }
LiveData简介
LiveData是一个可观察的数据持有者类。与常规可观察性不同,LiveData具有生命周期感知能力,这意味着它尊重其他应用程序组件(例如Activity、Fragment或Service)的生命周期。这种感知确保LiveData只更新处于活动生命周期状态(Observer 的 Lifecycle 对象处于 STARTED 或者 RESUMED 状态)的应用程序组件观察者。
LiveData 的优点
- 具有生命周期感知能力,可以做到在组件处于激活状态的时候才会回调相应的方法,从而刷新相应的 UI。
- 不用担心发生内存泄漏
- 当 config 导致 Activity 重新创建的时候,不需要手动取处理数据的储存和恢复。它已经帮我们封装好了。(需要使用ViewModel)
- 当 Actiivty 不是处于激活状态的时候,如果你想 Livedata setValue 之后立即回调 obsever 的 onChange 方法,而不是等到 Activity 处于激活状态的时候才回调 obsever 的 onChange 方法,你可以使用 ObserveForever 方法,但是你必须在 onDestroy 的时候 removeObserver。
LiveData 使用
LiveData 引入
-
android.support 形式
implementation "android.arch.lifecycle:livedata:1.1.1"
-
androidx 支持(如下方式引入,包含了ViewModel和LiveData)
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0" annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.0.0"
LiveData 基本使用
-
直接使用默认值设置
// 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>
-
点击事件修改值之后实时更新
// 只需要在 Activity 的 onCreate() 方法中增加以下代码即可 // 增加改变监听 userViewModel.userLiveData.observe(this, Observer {user -> text_view.text = user.toString() }) // 点击按钮,改变User bt_change.setOnClickListener { userViewModel.userLiveData.postValue(User("李四",28,"湖南省长沙市")) }
LiveData 进阶使用
-
map() :把一个数据类型变换为另外一个数据类型
// 将 User 对象变为 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 })
-
switchMap() : 把一个数据变化为另外一个 LiveData
// 在回调中创建 LiveData 类型数据返回 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 })
-
MediatorLiveData : LiveData的一个子类,允许合并多个LiveData源。MediatorLiveData对象的观察者随后会在任何原始LiveData源对象更改时触发
/ 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():只能在主线程设置Value
- postValue():可以在子线程设置Value
ViewModel+LiveData+DataBinding使用
简书:ViewModel+LiveData+DataBinding使用
CSDN:ViewModel+LiveData+DataBinding使用