美文网首页Android-JetpackAndroid开发经验谈
Jetpack架构组件 — LiveData与ViewModel

Jetpack架构组件 — LiveData与ViewModel

作者: e240c12aa0ad | 来源:发表于2020-05-18 15:20 被阅读0次
    Jetpack架构组件 — LiveData与ViewModel入坑详解

    前言

    前一篇文章我们讲解了Lifecycle的具体使用,为了更好的理解,本篇我们将LiveData和ViewModel放在一起讲解,通过简单的Demo来说明二者之间的协同工作。那么我们为什么要使用LiveData和ViewModel呢?他们有什么优势呢? 在LiveData出现之前,一般状态分发我们使用EventBus或者RxJava,这些都很容易出现内存泄漏问题,而且需要我们手动管理生命周期。而LiveData则规避了这些问题,LiveData是一个持有Activity、Fragment生命周期的数据容器。当数据源发生变化的时候,通知它的观察者更新UI界面。同时它只会通知处于Active状态的观察者更新界面,如果某个观察者的状态处于Paused或Destroyed时那么它将不会收到通知。所以不用担心内存泄漏问题。ViewModel将视图和逻辑进行了分离。Activity或者Fragment只负责UI显示部分。具体的网络请求或者数据库操作则由ViewModel负责。这样避免了视图的臃肿和代码的耦合。通过下面这张ViewModel生命周期可以看出,当屏幕发生旋转而导致Activity被销毁并重新创建时,ViewModel并没有被销毁,从而帮助我们在Activity重新创建后获取数据更新UI。它和onSaveInstanceState方法相比更有优势,因为onSaveInstanceState方法只不适合大量数据的恢复操作,只能恢复少量并且被序列化和反序列化的数据,而ViewModel不仅支持大量数据,还不需要序列化、反序列化操作。 Jetpack架构组件 — LiveData与ViewModel入坑详解

    基本用法

    首先我们在build.gradle中添加依赖:

    def lifecycle_version = "2.1.0"
    // ViewModel and LiveData
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"/
    

    然后我们创建ViewModel类,创建类继承ViewModel,并在其中创建LiveData:

    class SecondViewModel : ViewModel() {
    
    var userData: MutableLiveData<UserInfo> = MutableLiveData()
    /**
         *  模拟获取数据
         */
    fun getUserInfo() {
    
    val user = UserInfo("李四",(1000..5000).random())
            userData.postValue(user)
    
        }
    }
    

    因为LiveData是抽象类,MutableLiveData是它的一个实现类。其中定义了postValue和setValue用来通知观察者更新数据。postValue为异步操作。setValue为同步操作。接着我们在Activity中创建ViewModel并将UI组件和LiveData进行绑定以便进行数据的更新。

    class SecondActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
            setContentView(R.layout.activiry_second)
    
            val secondViewModel = ViewModelProviders.of(this).get(SecondViewModel::class.java)
    
            secondViewModel.userData.observe(this, Observer {
                mTvShow.text = "姓名:${it.name} \n薪水:${it.salary}"
            })
    /**
             * 模拟数据源更新
             */
            mBtnData.setOnClickListener {
                secondViewModel.getUserInfo()
            }
        }
    }
    
    这里通过ViewModelProviders来获取ViewModelProvider在通过get方法来获取ViewModel实例。我们通过button按钮注册了一个点击事件来模拟数据源数据的更新。 Jetpack架构组件 — LiveData与ViewModel入坑详解

    数据转换

    如果我们想对从服务端获取到的数据进行修改可以使用Transformations操作符。分为Map和switchMap两种。switchMap需要返回一个LiveData对象。Transformations.map

    Transformations.map(secondViewModel.userData, object : Function<UserInfo, UserInfo> {
    override fun apply(userInfo: UserInfo): UserInfo {
            userInfo.name = "张三"
    return userInfo
        }
    
    
    }).observe(this, Observer {
        mTvShow.text = "姓名:${it.name} \n薪水:${it.salary}"
    })
    

    这就将name重新赋值为“张三”。Transformations.switchMap比如我们有些数据需要依赖其他数据进行查询,就可以使用switchMap。

    Transformations.switchMap(secondViewModel.userData, object : Function<UserInfo, LiveData<UserInfo>> {
    override fun apply(userInfo: UserInfo): LiveData<UserInfo> {
    return secondViewModel.getUserName(userInfo)
            }
        }).observe(this, Observer {
        mTvShow.text = "姓名:${it.name} \n薪水:${it.salary}"
    })
    

    在ViewModel中定义getUserName方法

    fun getUserName(userInfo: UserInfo): LiveData<UserInfo> {
        userInfo.name = userInfo.name + "switchMap"
        switchMapData.value = userInfo
    return switchMapData
    }
    

    MediatorLiveData

    当我们页面需要多个不同的数据源的时候,如果我们都是单独的使用LiveData,会导致Activity中定义很多observe,出现很多多余的代码。MediatorLiveData就为解决这个问题的。它可以将多个LiveData合并在一起,只需要定义一次observe就可以。

    var data1: MutableLiveData<UserInfo> = MutableLiveData()
    var data2: MutableLiveData<UserInfo> = MutableLiveData()
    var mediatorLiveData: MediatorLiveData<UserInfo> = MediatorLiveData()
    
    val user1 = UserInfo("李四1", (1000..5000).random())
    val user2 = UserInfo("李四2", (1000..5000).random())
    
    data1.postValue(user1)
    data2.postValue(user2)
    
    mediatorLiveData.addSource(data1, object : Observer<UserInfo> {
    override fun onChanged(info: UserInfo) {
            mediatorLiveData.value = info
        }
    
    })
    
    mediatorLiveData.addSource(data2, object : Observer<UserInfo> {
    override fun onChanged(info: UserInfo) {
            mediatorLiveData.value = info
        }
    })
    

    这里我们定义了两个MutableLiveData表示正常的数据获取。MediatorLiveData通过addSource方法将data1和data2合并一起组成新的LiveData。onChanged回调表示的是当data1和data2数据源数据发送变化的时候进行回调。通知界面UI进行数据刷新。我们在Activity中使用:

    secondViewModel.mediatorLiveData.observe(this, Observer {
    if (it.name.contains("1")) {
            mTvShow.text = "姓名:${it.name} \n薪水:${it.salary}"
        } else {
            mTvShowOther.text = "姓名:${it.name} \n薪水:${it.salary}"
        }
    })
    

    这里就简单的通过name来判断不同的数据源类型。这样就将data1和data2首次请求的数据在界面展示了。上文也讲了onChanged是监听data1和data2数据变化的。这里我们在XML布局文件中新加一个button按钮用来模拟数据源变化。然后在ViewModel中第一模拟刷新方法:

    /**
    * 模拟data1和data2数据源改变
    */
    fun update() {
    
    val updateUser1 = UserInfo("李四1 update", (1000..5000).random())
    val updateUser2 = UserInfo("李四2 update", (1000..5000).random())
    
    data1.postValue(updateUser1)
    data2.postValue(updateUser2)
    
    }
    
    postValue执行完成后onChanged方法将接受到回调并通知UI更新数据。 Jetpack架构组件 — LiveData与ViewModel入坑详解

    扩展LiveData

    如果观察者的生命周期处于STARTED或RESUMED状态,则LiveData认为观察者处于活动状态。如果我们知道什么时候是active和inactive,那么我们可以自己实现LiveDta。所以LiveData提供了两个方法,分别为onActive()与onInactive()。并给出了官方Demo:

    class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val stockManager = StockManager(symbol)
    
    private val listener = { price: BigDecimal ->
            value = price
        }
    
    override fun onActive() {
            stockManager.requestPriceUpdates(listener)
        }
    
    override fun onInactive() {
            stockManager.removeUpdates(listener)
        }
    }
    

    onActive方法被调用说明现在有活动着的观察者,所以添加监听以进行数据的更新。onInactive方法被调用说明没有活动的观察者所以要移除监听。我们使用StockLiveData:

    class MyFragment : Fragment() {
    
    override fun onActivityCreated(savedInstanceState: Bundle?) {
            StockLiveData.get(symbol).observe(this, Observer<BigDecimal> { price: BigDecimal? ->
    // Update the UI.
            })
        }
    

    相关文章

      网友评论

        本文标题:Jetpack架构组件 — LiveData与ViewModel

        本文链接:https://www.haomeiwen.com/subject/lbiuohtx.html