Android架构组件之ViewModel和LiveData

Posted dfqin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android架构组件之ViewModel和LiveData相关的知识,希望对你有一定的参考价值。

关于应用架构,Google官方现在主推MVVM架构,官方推出的JetPack库提供了一系类支持MVVM架构,其中最核心的两个类是ViewModel和LiveData。

在MVVM架构中,View通常指Activity和Fragment,主要用来根据数据渲染UI,而Model主要负责数据的获取,这里通常包含获取网络数据和本地缓存数据,而ViewModel作为View和Model的桥梁,主要负责UI数据的处理,官方提供了ViewModel类作为一种实现。LiveData作为一种可观察的数据存储类,可以很好在支持ViewModel处理好的数据通知UI的更新。

ViewModel

主要负责存储和管理和界面相关的数据。很多地方都提到ViewModel感知生命周期,查看源码可以得知并不是这样,它只不过在config变化导致Activity销毁重建期间不会销毁。

ViewModel对于开发者来说,就是Activity或Fragment的一个成员变量,它的初始化代码通常是这样的:

viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)

而它的底层实现过程是这样的,FragmentActivity或Fragment有一个成员变量mViewModelStore用来存储ViewModel,ViewModelProviders只是个包装器,它会从当前activity或fragment的ViewModelStore中取ViewModel,如果没有的话就创建一个并存储到ViewModelStore中。至于文档中提到的config变化不会销毁,是因为config变化引起的销毁重建,FragmentActivity会缓存ViewModelStore,如下代码所示,在onRetainNonConfigurationInstance函数中保存了ViewModelStore。但是正常的内存不足页面销毁重建时,ViewModel是会重新创建的,我们可以看到onSaveInstanceState中没有对ViewModelStore做缓存的,并且在onDestroy中进行了销毁。

    protected void onCreate(@Nullable Bundle savedInstanceState) 
        this.mFragments.attachHost((Fragment)null);
        super.onCreate(savedInstanceState);
        FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
        if (nc != null && nc.viewModelStore != null && this.mViewModelStore == null) 
            this.mViewModelStore = nc.viewModelStore;
        
        ......
    


    @NonNull
    public ViewModelStore getViewModelStore() 
        if (this.getApplication() == null) 
            throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call.");
         else 
            if (this.mViewModelStore == null) 
                FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
                if (nc != null) 
                    this.mViewModelStore = nc.viewModelStore;
                

                if (this.mViewModelStore == null) 
                    this.mViewModelStore = new ViewModelStore();
                
            

            return this.mViewModelStore;
        
    


    //config变化时保存数据
    public final Object onRetainNonConfigurationInstance() 
        Object custom = this.onRetainCustomNonConfigurationInstance();
        FragmentManagerNonConfig fragments = this.mFragments.retainNestedNonConfig();
        if (fragments == null && this.mViewModelStore == null && custom == null) 
            return null;
         else 
            FragmentActivity.NonConfigurationInstances nci = new FragmentActivity.NonConfigurationInstances();
            nci.custom = custom;
            nci.viewModelStore = this.mViewModelStore;
            nci.fragments = fragments;
            return nci;
        
    

LiveData

1、简介  

看官方文档我们知道LiveData是一种可观察的数据存储类,它具有感知生命周期的能力。通常ViewModel是靠LiveData通知View层数据变化的,Activity、Fragment和Service监听LiveData,当数据变化时会收到通知做相应的UI更新工作。上面说了LiveData有生命周期感知能力,所以当Activity处于非活跃状态时,是不会收到通知的,当Activity再次处于活跃状态时,会重新收到数据变化的通知。我们可以看下典型的使用的方式:

       // void observe(LifecycleOwner owner, Observer<? super T> observer)

        mViewModel?.phone?.observe(this, Observer 
            user_phone.setText(it ?: "")
        )

上面的代码是写在Activity或Fragment中的,phone就是ViewModel中的一个LiveData,我们可以看到在监听LiveData时同时传了参数LifecycleOwner,LiveData就是通过这个LifecycleOwner感知生命周期的,当phone的值发生变化并且当前页面(LifecycleOwner)处于活跃状态时,会收到通知更新UI,如果页面不处于活跃状态不会收到通知的。当页面从不活跃状态变为活跃状态时,中间数据发生过变化的话会收到通知。

2、使用 

在UI层(Activity、Fragment)向LiveData注册监听者,接收数据变化的通知,代码如上面的图所示;LiveData没有公开的方法更新数据,子类MutableLiveData公开了两个方法用来更新存储的值setValuepostValue,在UI线程可以直接使用setValue,在非UI线程使用postValue;

3、扩展LiveData 

前面说过LiveData可以感知声明周期,如果部分业务请求对生命周期敏感,可以扩展LiveData,根据生命周期回调做相应的工作:

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)
    

4、LiveData转换 -- Transformations

如果想在LiveData的值返回给观察者前进行处理,可以使用Transformations类的map()和switchMap()方法,这两个方法类似,都是以原始LiveData和一个函数做入参,返回一个新的LiveData,区别是这个函数入参的返回值,一个是返回处理过后的数据,一个是返回新的LiveData,看官方文档有点难理解,但是看源码就比较清晰,他们都是返回了一个新的MediatorLiveData对象,对原始LiveData做了处理,可以看下官方例子和map()源码

// userLiveData值更新会触发userName更新,用户监听userName即可;
// 原始User对象用来生成userName的值
val userLiveData: LiveData<User> = UserLiveData()
val userName: LiveData<String> = Transformations.map(userLiveData) 
    user -> "$user.name $user.lastName"



//userId值更新会触发user更新,用户监听user即可;
//原始userId用来生成新的LiveData
private fun getUser(id: String): LiveData<User> 
  ...

val userId: LiveData<String> = ...
val user = Transformations.switchMap(userId)  id -> getUser(id) 


//map()源码
public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source, @NonNull final Function<X, Y> mapFunction) 
    final MediatorLiveData<Y> result = new MediatorLiveData();
    result.addSource(source, new Observer<X>() 
        public void onChanged(@Nullable X x) 
            result.setValue(mapFunction.apply(x));
        
    );
    return result;

5、LiveData合并 ---- MediatorLiveData 

MediatorLiveData是LiveData的一个子类,它可以将多个LiveData合并,有任何一个LiveData变化都可以触发通知MediatorLiveData的观察者。上面的Transformations的map()和switchMap()都是使用的MediatorLiveData实现的。

        var data1 = MutableLiveData<String>()
        var data2 = MutableLiveData<String>()
        
        var mediator1 = MediatorLiveData<String>()
        mediator1.addSource(data1) 
            mediator1.value = "handled $it"
        
        mediator1.addSource(data2) 
            mediator1.value = "handled $it"
        
        
        var mediator2 = MediatorLiveData<String>().apply  
            this.addSource(data1)
                this.value = "handled $it"
            
            this.addSource(data2)
                this.value = "handled $it"
            
        

以上是关于Android架构组件之ViewModel和LiveData的主要内容,如果未能解决你的问题,请参考以下文章

Android官方架构组件之LiveData + ViewModel + Room 源码分析

Android架构组件之ViewModel

Android架构组件之ViewModel

Android官方架构组件介绍之ViewModel

Android架构组件之ViewModel和LiveData

Android架构组件之ViewModel和LiveData