注意:本篇学习笔记主要根据官方文档处理生命周期,LiveData,ViewModel部分学习,点击即可查看官方文档。
使用生命周期感知型组件
生命周期感知型组件可执行操作来响应另一个组件(如Activity和Fragment)的生命周期状态的变化。androidx.lifecycle软件包提供了可用于构建生命周期感知型组件的类和接口,这些组件可以根据Activity或Fragment的当前生命周期状态自动调整其行为。
由于在Android框架中定义的大多数应用组件都存在生命周期,而生命周期是由操作系统或进程中运行的框架代码管理,所以应用必须遵循生命周期,在合适的生命周期内执行合适的操作。如果不遵循这些生命周期,可能会引发内存泄漏甚至奔溃。
假设有一个在屏幕上显示当前位置的Activity,常见的实现可能如下:
internal class LocationUtils(
private val context: Context,
private val callback: (Location) -> Unit
) {
fun start(){
//开始请求位置信息
}
fun stop(){
//停止请求位置信息
}
}
这样我们就定义了一个获取位置信息的类,然后我们在Activity中可以这样使用:
class LifecycleTest1Activity : BaseActivity<ActivityLifecycleTest1Binding>() {
private lateinit var locationUtils: LocationUtils
override fun getLayoutId(): Int = R.layout.activity_lifecycle_test1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
locationUtils = LocationUtils(this){
Log.e("TAG","获取到的位置信息$it")
}
}
override fun onStart() {
super.onStart()
locationUtils.start()
}
override fun onStop() {
super.onStop()
locationUtils.stop()
}
}
上面的代码是没有问题的,但是在真实的使用的场景中,在同一个页面中我们可能会有很多的管理界面和其它组件的调用,以响应生命周期的当前状态。管理多个组件会在生命周期方法(如onStart或者onStop方法中)放置大量的代码,这就会使得它们难以维护。
此外,无法保证组件会在Activity或Fragment停止之前启动。在我们需要长时间运行的操作中(如onStart()中检查某种配置)尤其如此。这可能会导致出现一种竞争条件,在这种条件下onStop()会在onStart()之前结束,这使得组件停留的时间比所需要的时间更长。下面是官方代码:
class MyActivity : AppCompatActivity() {
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...) {
myLocationListener = MyLocationListener(this) { location ->
// update UI
}
}
public override fun onStart() {
super.onStart()
Util.checkUserStatus { result ->
// what if this callback is invoked AFTER activity is stopped?
if (result) {
myLocationListener.start()
}
}
}
public override fun onStop() {
super.onStop()
myLocationListener.stop()
}
}
声明周期
Lifecycle是一个类,用于存储有关组件(如Activity或Fragment)的生命周期信息,并允许其它对象观察此状态。
Lifecycle使用两种主要枚举跟踪其关联组件的生命周期状态:
Event
从框架和Lifecycle类分派的生命周期事件,这些事件映射到Activity或Fragment中的回调事件。
State
由Lifecycle对象跟踪的组件的当前状态。

可以将状态看作途中的节点,将事件看作这些节点之间的边。
类可以通过向其方法添加注解来监控组件的生命周期的状态,然后,可以通过调用Lifecycle类的addObserver()方法并传递观察者的实例来添加观察者,如:
class MyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun connectionListener(){
Logs.e("开始连接")
}
fun disconnectionListener(){
Logs.e("断开连接")
}
}
//使用
myLifecycleOwner.getLifecycle().addObserver(MyObserver())
在上面的示例中,myLifecycleOwner对象实现了LifecycleOwner接口。
LifecycleOwner
LifecycleOwner是单一方法接口,表示类具有Lifecycle.它具有一种方法(即getLifecycle()),该方法必须由类进行实现,如果尝试管理整个应用的声明周期,则需要使用ProcessLifecycleOwner
此接口从各个类(如Fragment和AppcompatActivity)抽象化Lifecycle的所有权,并允许编写与这些类搭配使用的组件。任何自定义应用类均可实现LifecycleOwner接口。
实现LifecycleObserver的组件可与实现LifecycleOwner的组件无缝协同工作,因为所有者可以提供生命周期,而观察者可以注册以观察声明周期。
对于上面的位置跟踪示例,可以让LocationUtils类实现LifecycleObserber接口,然后在Activity的onCreate()方法中对其进行初始化。这样,LocationUtils类便可以自动根据Activity的生命周期执行相应的操作。同时,这样做意味着对生命周期状态的变化做出响应的逻辑会在LocationUtils类内部。让各个组件存储自己的逻辑,可使Activity和Fragment的逻辑更易于管理。
为了实现上面的效果,主要分成以下三步:
- 在
LocationUtils类实现LifeObserver接口,然后再需要监听的方法上面添加需要添加的生命周期状态的注释:
internal class LocationUtils(
private val context: Context,
private val callback: (Location) -> Unit
) : LifecycleObserver {
//在onStart中开始请求
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun start(){
//开始请求位置信息
Logs.e("开始请求")
}
//在onStop之后停止请求
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stop(){
//停止请求位置信息
Logs.e("停止请求")
}
}
-
在
Activity中添加需要实现的LifecycleOwner接口,这里由于Support Library 26.1.0及更高版本的Activity和Fragment中已经默认实现了这个接口,所以可以省略,主要是要看一下编译的版本。 -
在
Activity的onCreate()方法中添加LocationUtils的对象即可:
lifecycle.addObserver(locationUtils)
运行程序之后,会出现如下打印的信息:
2020-04-15 17:24:19.810 4318-4318/com.example.myapplication E/com.example.myapplication: onCreate() finish
2020-04-15 17:24:19.815 4318-4318/com.example.myapplication E/com.example.myapplication: onStart()
2020-04-15 17:24:19.815 4318-4318/com.example.myapplication E/com.example.myapplication: 开始请求
2020-04-15 17:24:19.816 4318-4318/com.example.myapplication E/com.example.myapplication: onResume()
2020-04-15 17:24:29.030 4318-4318/com.example.myapplication E/com.example.myapplication: onPause()
2020-04-15 17:24:29.561 4318-4318/com.example.myapplication E/com.example.myapplication: 停止请求
2020-04-15 17:24:29.563 4318-4318/com.example.myapplication E/com.example.myapplication: onStop()
2020-04-15 17:24:29.566 4318-4318/com.example.myapplication E/com.example.myapplication: onDestroy()
可以看到,确实是在相应的生命周期的方法中执行了相应的操作。
但是,这样仍然是会出现我们之前所说的问题的,所以在官方文档中,对LocationUtils也做了相应的修改,如:
internal class LocationUtils(
private val context: Context,
private val lifecycle: Lifecycle,
private val callback: (Location) -> Unit
) : LifecycleObserver {
private var enable = false
//在onStart中开始请求
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun start() {
//开始请求位置信息
if (enable)
Logs.e("开始请求")
}
//在onStop之后停止请求
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stop() {
//停止请求位置信息
Logs.e("停止请求")
}
fun enable() {
enable = true
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
//如果没有开始连接,则在这里开始连接
start()
}
}
}
我们主要在LocationUtils中添加了一个enable属性和一个enable()方法,由于enable默认为false,所以虽然我们会监听OnStart()生命周期,但是其实并不会执行操作。然后我们在enable()方法中做判断,当修改了enable的状态的时候会判断当前处于何种生命周期的状态,从而决定是否要执行相应的方法。
override fun onCreate(...) {
myLocationListener = MyLocationListener(this, lifecycle) { location ->
// update UI
}
Util.checkUserStatus { result ->
if (result) {
myLocationListener.enable()
}
}
}
在上面,我们在判断完状态之后才会去调用LocationUtils里面的enable()开启定位,在enable()中就会对当前的页面状态进行判断,然后决定是否要开启请求。
至此,我们就可以使用生命周期感知型组件了。
实现自定义LifecycleOwner
如果我们有一个自定义类并且希望使其成为LifecycleOwner,那么就需要使用LifeCycleRegister将事件转发到该类,如下:
class MyActivity : Activity(), LifecycleOwner {
private lateinit var lifecycleRegistry: LifecycleRegistry
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleRegistry = LifecycleRegistry(this)
lifecycleRegistry.markState(Lifecycle.State.CREATED)
}
public override fun onStart() {
super.onStart()
lifecycleRegistry.markState(Lifecycle.State.STARTED)
}
override fun getLifecycle(): Lifecycle {
return lifecycleRegistry
}
}
总的来说,Lifecycle允许我们将Activity或Fragment等组件的声明周期暴露给其它组件,这样可以将Activity和其它组件进行解耦,其它组件在自己的类中就可以根据不同的生命周期执行不同的操作,不用再去到Activity的声明周期的方法中执行操作了。
LiveData
LiveData是一种可观察的数据存储类,与常规的可观察类不同,LiveData具有生命周期感知能力,也就是说它遵循其它组件(如Activity,Fragment,Service)的生命周期。这种感知能力可确保LiveData仅更新处于活跃生命周期状态的应用组件观察者。
如果观察者(由Observer类表示)的声明周期处于STARTED或RESUMED状态,则LiveData会认为该观察者处于活跃状态。LiveData只会将更新通知给活跃的观察者。为观察LiveData对象而注册的非活跃观察者不会收到更改通知。
可以注册与实现LifecycleOwner接口的对象配对的观察者。有了这种关系,当相应的Lifecycle对象的状态变为DESTROYED时,便可移除此观察者。这对于Activity和Fragment特别有用,因为它们可以放心地观察LiveData对象而不必担心泄露(当Activity或Fragment的生命周期被销毁时,系统会立即退订它们)
使用LiveData对象
可以按照以下步骤使用LiveData对象:
- 创建
LiveData的实例以存储某种类型的数据,这通常在ViewModel中完成 - 创建可定义
onChanged()方法的Observer对象,该方法可以控制当LiveData对象存储的数据更改时会发生什么。通常情况下,可以在界面控制器(Activity或Fragment)中创建Observer对象 - 使用
observer()方法将Observer对象附加到LiveData对象。observer()方法会采用LifecycleOwner对象。这样会使Observer对象订阅LiveData对象,以使其收到有关更改的通知。通常情况下,可以在界面控制器(Activity或Fragment)中附加Observer对象。
注意:可以通过使用observerForever(Observer)方法来注册未关联LifecycleOwner对象的观察者。在这种情况下,观察者会被视为始终处于活跃状态,因此它始终会收到关于更改的通知。同时,可以调用removeObserver(Observer)方法来移除观察者。
当更新存储在LiveData对象中的值时,它会触发所有已注册的观察者(只要附加的LifecycleOwner处于活跃状态)。
创建LiveData对象
LiveData是一种可用于任何数据的封装容器,其中包括可实现Collections的对象,如List。LiveData对象通常存储在ViewModel对象中,并可通过getter方法进行访问,如:
class NameViewModel: ViewModel() {
//创建一个包含String类型的LiveData
val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
}
最初,LiveData中的数据并未经过设置。
需要注意的是:确保将用于更新界面的LiveData对象存储在ViewModel对象中,而不是将其存储在Activity或Fragment中,原因如下:
-
避免
Activity和Fragment过于庞大。现在,这些界面控制器负责显示数据,但不负责存储数据状态 -
将
LiveData实例与特定的Activity或Fragment实例分开,并使对象在配置更改后继续存在。
观察LiveData对象
在大多数情况下,应用组件的onCreate()方法是开始观察LiveData对象的正确着手点,这是因为:
- 确保系统不会从
Activity或者Fragment的onResume()方法进行冗余调用; - 确保
Activity或者Fragment变为活跃状态后具有可以立即显示的数据。一旦应用组件处于STARTED状态,就会从它正在观察的LiveData对象接收最新值。只有在设置了要观察的LiveData对象时,才会发生这种情况。
通常,LiveData仅在数据发生更改时才发送更新,并且仅发送给活跃观察者。此行为的一种例外情况是:观察者从非活跃状态更改为活跃状态时也会收到更新。此外,如果观察者第二次从非活跃状态更改为活跃状态,则只有在自上次变为活跃状态以来值发生了更改时,它才会收到更新。
以下代码说明了如何开始观察LiveData对象:
override fun initUi() {
//获取ViewModel
model = ViewModelProviders.of(this)[NameViewModel::class.java]
//创建更新UI的观察者
val nameObserver = Observer<String>{
mBinding.tvName.text = it
}
//观察LiveData,通过observer方法关联生命周期所有者和观察者
model.currentName.observe(this,nameObserver)
}
在传递nameObserver参数的情况下调用observer()后,系统会立即调用onChange(),从而提供currentName中存储的最新值,如果LiveData对象尚未在currentName中设置值,则不会调用onChange()。
更新LiveData对象
LiveData没有公开可用的方法来更新存储的数据,MutableLiveData类将公开setValue(T)和postValue(T)方法。如果需要修改存储在LiveData对象中的值,则必须使用这些方法。通常情况下会在ViewModel中使用MutableLiveData,然后ViewModel只会向观察者公开不可变的LiveData对象。
设置观察者关系后,就可以更新LiveData对象中的值,如下所示:点击按钮的时候会更新新值:
if(view?.id == R.id.btn_change_value){
model.currentName.value = "张三"
}
这样,点击了上面的按钮之后就会更新LiveData中存储的数据,然后TextView中的数据也会立即改变。
至于setValue(T)和postValue(T)的区别在于,setValue(T)可以在UI线程更新数据,如果当前是在工作线程,那么就需要使用postValue(T)。
扩展LiveData
如果观察者的生命周期处于STARTED或RESUMED状态,则LiveData会认为该观察者处于活跃状态。以下代码说明了如何扩展LiveData类:
class StockLiveData(symbol: String) : LiveData<BigDecimal>(){
private val stockManager: StockManager = StockManager(symbol)
private val listener = {
price: BigDecimal -> value = price
}
override fun onActive() {
super.onActive()
stockManager.requestPriceUpdate(listener)
}
override fun onInactive() {
super.onInactive()
stockManager.removeUpdates(listener)
}
}
上面的程序演示了通过继承LiveData类,来实时更新股票价格的数据。价格监听器主要包含以下重要方法:
- 当
LiveData对象具有活跃观察者时,会调用onActive()方法,这意味着,需要从此方法开始观察股票更新。 - 当
LiveData对象没有任何活跃观察者时,会调用onInactive()方法,由于没有观察者在监听,此时会调用移除价格监听器。
可以在Activity或者Fragment中使用这个类,使用方式和上面的MutableLiveData是一样的:
stockLiveData = StockLiveData("股票")
stockLiveData.observe(this,Observer<BigDecimal>{
mBinding.tvName.text = it.toEngineeringString()
})
只不过由于在onActive()方法中我们直接进行了赋值操作,所以在页面打开的时候就可以看到TextView中已经有相应的数据了。
LiveData对象具有生命周期感知能力,这一事实意味着可以在多个Activity,Fragment和Service之间共享它们。因此,可以将LiveData类实现为单一实例,如下所示:
class StockLiveData(symbol: String) : LiveData<BigDecimal>(){
private val stockManager: StockManager = StockManager(symbol)
private val listener = {
price: BigDecimal -> value = price
}
override fun onActive() {
super.onActive()
stockManager.requestPriceUpdate(listener)
}
override fun onInactive() {
super.onInactive()
stockManager.removeUpdates(listener)
}
companion object{
private lateinit var instance : StockLiveData
fun get(symbol: String) : StockLiveData{
instance = if(::instance.isInitialized) instance else StockLiveData(symbol)
return instance
}
}
}
使用方式也是一样的:
StockLiveData.get("股票").observe(this, Observer<BigDecimal> {
mBinding.tvName.text = it.toPlainString()
})
转换LiveData
有时候我们可能希望在LiveData对象分派给观察者之前对存储在其中的值进行更改,或者可能需要更具另一个实例的值返回不同的LiveData实例。Lifecycle软件包提供了Transformations`类,该类提供了这些辅助方法。
Transformations.map()
对存储在LiveData对象中的值应用函数,并将结果传播到下游。
val userLiveData: LiveData<User> = UserLiveData()
val userInfo: LiveData<String> = Transformations.map(userLiveData){
user -> "我是${user.name},今年${user.age}岁"
}
userInfo.observe(this, Observer<String> {
mBinding.tvName.text = it
})
Transformations.switchMap()
与Map类似,对存储在LiveData对象中的值应用函数,并将结果解封和分派到下游,传递给switchMap()的函数必须返回LiveData对象,如下所示:
//根据用户id返回一个用户信息
private fun getUserWithId(userId: String) : LiveData<User> = MutableLiveData<User>(User("姓名$userId",10,"123",null))
//使用switchMap获得一个`LiveData<User>`
val userId : MutableLiveData<String> = MutableLiveData<String>()
userId.value = "100"
val user: LiveData<User> = Transformations.switchMap(userId){
getUserWithId(it)
}
//设置给textView
user.observe(this,Observer<User>{
mBinding.tvName.text = "我是${it.name}"
})
同时,我们可能会用到其它一些转换,要实现自己的转换,可以使用MediatorLiveData类,改类可以监听其它LiveData对象并处理它们发出的事件。
合并多个LiveDatayuan
MediatorLiveData是LiveData的子类,允许合并多个LiveData源,只要任何原始的LiveData源发生更改,就会触发MediatorLiveData对象的观察者。
ViewModel
ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel类让数据可在发生屏幕旋转等配置更改后继续存在。
Android框架可以管理界面控制器(如Activity或Fragment)的生命周期。Android框架可能会决定销毁或重新创建界面控制器,以响应完全不受用户控制的某些用户操作或设备事件。
如果系统销毁或重新创建界面控制器,则存储在其中的任何临时性界面相关数据都会丢失。例如,应用的某个Activity中可能包含用户列表,因配置更改而重新创建Activity后,新Activity必须重新提取用户列表。对于简单的数据,Activity可以使用onSaveInstanceState()方法从onCreate()中的Bundle中恢复其数据,但是此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。
另一个问题是,界面控制器经常需要进行异步调用,这些调用可能需要一些时间才能返回结果。界面控制器需要管理这些调用,并确保系统再其销毁后清理这些调用以避免潜在的内存泄露。此项管理需要大量的维护操作,并且在因配置更改而重新创建对象的情况下,会造成资源的浪费,因为对象可能需要重新发出已经发出过的调用。
诸如Activity或Fragment之类的界面控制器主要用于显示界面数据,对用户操作做出响应或处理操作系统通信(如权限请求)。如果要求界面控制器也负责从网络或数据库加载数据,那么会使类越发膨胀。为界面控制器分配过多的责任可能会导致单个类尝试自己处理应用的所有工作,而不是将工作委托给其它类。以这种方式为界面控制器分配过多的责任也会大大增加的是的难度。
总的来说,其实就是将界面控制器中有关数据的操作分离出去,使得界面控制器仅仅负责和用户的交互,显示数据给用户,接收用户的操作,至于数据怎么来的,怎么保存的,这些都不是界面控制器需要考虑的问题。
实现ViewModel
架构组件为界面控制器提供了ViewModel辅助程序类,该类负责为界面准备数据。在配置更改期间会自动保留ViewModel对象,以便它们存储的数据立即可供下一个Activity或Fragment实例使用。例如:如果需要在应用中显示用户列表,则需要确保将获取和保留该用户列表的责任分配给ViewModel,而不是Activity或Fragment。
class MyViewModel: ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData<List<User>>().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> = users
private fun loadUsers(){
//在异步线程中获取用户信息
}
定义了上面的ViewModel之后就可以从Activity访问上面的用户列表了。
val model = ViewModelProviders.of(this)[MyViewModel::class.java]
model.getUsers().observe(this,Observer<List<User>>{
//更新UI
})
需要注意的是:ViewModel绝不能引用视图,Lifecycle或可能存储对Activity上下文引用的任何类,以避免发生潜在的内存泄露。
ViewModel存在的时间比视图或LifecycleOwners的特定实例存在的时间更长。这同时意味着,可以更轻松地编写涵盖ViewModel的测试,因为它不了解视图和Lifecycle对象。ViewModel对象可以包含LifecycleObservers,如LiveData对象。但是,ViewModel绝不能观察对生命周期感知型可观察对象(如LiveData)的更改。如果ViewModel需要Application上下文(例如查找系统服务),它可以扩展AndroidViewModel类并设置用于接收Application的构造函数,因为Application类会扩展Context。
ViewModel的生命周期
ViewModel对象存在的时间范围是获取ViewModel时传递给ViewModelProvider的Lifecyle。ViewModel将一直存在于内存中,直到限定其存在时间范围的Lifecycle永久消失:对于Activity是在Activity完成时,而对于Fragment,是在Fragment分离时。
下图说明了ViewModel的生命周期和Activity生命周期之间的关系,图片来源于官方文档,点击这里查看原文

通常在系统首次调用Activity对象的onCreate()方法时请求ViewModel。系统可能会在Activity的整个生命周期内多次调用onCreate()方法,如在旋转设备屏幕时。ViewModel存在的时间范围是从首次请求ViewMoel直到Activity完全销毁。
针对上面所说的多次调用同一个Activity的onCreate()方法,返回的是同一个ViewModel实例,通过查看源码可以知道,ViewModel保存在Activity内部的ViewModelStore对象中,ViewModelStore内部有一个HashMap来维护ViewModel列表,虽然执行ViewModelProviders.of(this)会返回不同的ViewModelProvider对象,但是由于每次都是从同一个ViewModelStore中获取ViewModel对象,因此可以保证多次执行onCreate()方法获取到的是同一个ViewModel实例。
在Fragment之间共享数据
Activity中的两个或多个Fragment之间需要相互通信是一种很常见的情况。假设有一种情况,在一个Fragment中的用户列表中选择一个用户,在另一个Fragment中要显示这个用户的详细信息。之前我们可以通过接口来处理这种情况,但是实现起来相对会繁琐一点。另外还需要掌握好设置Fragment中的数据的时机,否则可能会发生异常。
对于上面的问题,使用ViewModel则相对会比较容易解决,这个两个Fragment可以通过使用其Activity范围来共享ViewModel处理通信,如下所示:
//学生列表的Fragment
class StudentListFragment: Fragment() {
private lateinit var model: ShareUserViewModel
private lateinit var mBinding: FragmentStudentListBinding
private val students = mutableListOf<Student>()
private lateinit var adapter : MyRVAdapter<Student,ItemStudentListBinding>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.let {
ViewModelProviders.of(it)[ShareUserViewModel::class.java]
}?:throw Exception("尚未初始化Activity")
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mBinding = FragmentStudentListBinding.inflate(inflater,null,false)
return mBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
for(i in 1..10){
val student = Student("姓名$i",i+10,"1232131")
students.add(student)
}
mBinding.rvContent.layoutManager = LinearLayoutManager(context)
context?.apply {
adapter = object : MyRVAdapter<Student,ItemStudentListBinding>(this,R.layout.item_student_list,students){
override fun doClick(view: View, position: Int) {
super.doClick(view, position)
if(view.id == R.id.tv_name){
Logs.e("点击名称")
return
}
model.select(getItem(position))
}
}
mBinding.rvContent.adapter = adapter
}
}
}
//学生信息的Fragment
class StudentInfoFragment: Fragment() {
private lateinit var model: ShareUserViewModel
private lateinit var mBinding: FragmentStudentInfoBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this)[ShareUserViewModel::class.java]
}?:throw Exception("Activity尚未初始化")
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mBinding = FragmentStudentInfoBinding.inflate(inflater)
return mBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model.select.observe(this,Observer<Student>{
mBinding.student = it
})
}
}
//在Activity中显示上面两个Fragment,点击第一个Fragment中的某一个学生,会在第二个Fragment中立即更新点击的学生的信息
class ViewModelTest1Activity : BaseActivity<ActivityViewModelTest1Binding>() {
private val mUserListFragment by lazy {
StudentListFragment()
}
private val mUserInfoFragment by lazy {
StudentInfoFragment()
}
override fun getLayoutId(): Int = R.layout.activity_view_model_test1
override fun initUi() {
}
override fun initData() {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fl_user_list,mUserListFragment)
transaction.replace(R.id.fl_user_info,mUserInfoFragment)
transaction.commit()
}
}