嗨,你们好,面试真题系列又来了,今天咱们说说MVVM架构里的两大组件:ViewModel和LiveData。
仍是老样子,提出问题,作出解答。java
ViewModel 是什么?面试
ViewModel 为何被设计出来,解决了什么问题?架构
说说ViewModel原理。app
LiveData 是什么?框架
LiveData 为何被设计出来,解决了什么问题?ide
说说LiveData原理。post
若是看过我上一篇文章的小伙伴应该都有所了解,ViewModel
是MVVM架构的一个层级,用来联系View和model之间的关系。而咱们今天要说的就是官方出的一个框架——ViewModel。学习
ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据this
官方是这么介绍的,这里面有两个信息:spa
ViewModel
的生命周期是做用于整个Activity的,因此就节省了一些关于状态维护的工做,最明显的就是对于屏幕旋转这种状况,之前对数据进行保存读取,而ViewModel
则不须要,他能够自动保留数据。其次,因为ViewModel
在生命周期内会保持局部单例,因此能够更方便Activity的多个Fragment
之间通讯,由于他们能获取到同一个ViewModel实例,也就是数据状态能够共享了。
ViewModel
层的根本职责,就是负责维护界面上UI的状态,其实就是维护对应的数据,由于数据会最终体现到UI界面上。因此ViewModel
层其实就是对界面相关的数据进行管理,存储等操做。
ViewModel
组件被设计出来以前,MVVM又是怎么实现ViewModel这一层级的呢?其实就是本身编写类,而后经过接口,内部依赖实现View和数据的双向绑定。
因此Google出这个ViewModel组件,无非就是为了规范MVVM
架构的实现,并尽可能让ViewModel这一层级只触及到业务代码,不去关心VIew层级的引用等。而后配合其余的组件,包括livedata,databindingrang
等让MVVM架构更加完善,规范,健硕。
其实上面已经说过一些了,好比:
1)不会由于屏幕旋转而销毁,减小了维护状态的工做
2)因为在做用域内单一实例的特性,使得多个fragment
之间能够方便通讯,而且维护同一个数据状态。
3)完善了MVVM
架构,使得解耦更加纯粹。
ViewModel2.0以前呢,其实原理是在Activity上add一个HolderFragment,而后设置setRetainInstance(true)
方法就能让这个Fragment在Activity重建时存活下来,也就保证了ViewModel的状态不会随Activity的状态所改变。
2.0以后,实际上是用到了Activity的onRetainNonConfigurationInstance()
和getLastNonConfigurationInstance()
这两个方法,至关于在横竖屏切的时候会保存ViewModel的实例,而后恢复,因此也就保证了ViewModel的数据。
首先,ViewModel的实例是经过反射获取的,反射的时候带上application的上下文,这样就保证了不会持有Activity或者Fragment等View的引用。而后实例建立出来会保存到一个ViewModelStore
容器里面,其实也就是一个集合类,这个ViewModelStore 类其实就是保存在界面上的那个实例,而咱们的ViewModel
就是里面的一个集合类的子元素。
因此咱们每次获取的时候,首先看看这个集合里面有无咱们的ViewModel
,若是没有就去实例化,若是有就直接拿到实例使用,这样就保证了惟一实例。最后在界面销毁的时候,会去执行ViewModelStore
的clear方法,去清除集合里面的ViewModel数据。一小段代码说明下:
public <T extends ViewModel> T get(Class<T> modelClass) { // 先从ViewModelStore容器中去找是否存在ViewModel的实例 ViewModel viewModel = mViewModelStore.get(key); // 若ViewModel已经存在,就直接返回 if (modelClass.isInstance(viewModel)) { return (T) viewModel; } // 若不存在,再经过反射的方式实例化ViewModel,并存储进ViewModelStore viewModel = modelClass.getConstructor(Application.class).newInstance(mApplication); mViewModelStore.put(key, viewModel); return (T) viewModel; } public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap<>(); public final void clear() { for (ViewModel vm : mMap.values()) { vm.onCleared(); } mMap.clear(); } } @Override protected void onDestroy() { super.onDestroy(); if (mViewModelStore != null && !isChangingConfigurations()) { mViewModelStore.clear(); } }
LiveData 是一种可观察的数据存储器类。与常规的可观察类不一样,LiveData 具备生命周期感知能力,意指它遵循其余应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
官方介绍以下,其实说的比较清楚了,主要做用在两点:
数据存储器类
。也就是一个用来存储数据的类。
可观察
。这个数据存储类是能够观察的,也就是比通常的数据存储类多了这么一个功能,对于数据的变更能进行响应。
主要思想就是用到了观察者模式
思想,让观察者和被观察者解耦,同时还能感知到数据的变化,因此通常被用到ViewModel中,ViewModel
负责触发数据的更新,更新会通知到LiveData
,而后LiveData再通知活跃状态的观察者。
var liveData = MutableLiveData<String>() liveData.observe(this, object : Observer<String> { override fun onChanged(t: String?) { } }) liveData.setVaile("xixi") //子线程调用 liveData.postValue("test")
LiveData
做为一种观察者模式设计思想,经常被和Rxjava
一块儿比较,观察者模式的最大好处就是事件发射的上游 和 接收事件的下游 互不干涉,大幅下降了互相持有的依赖关系所带来的强耦合性
。
其次,LiveData还能无缝衔接到MVVM
架构中,主要体如今其能够感知到Activity
等生命周期,这样就带来了不少好处:
不会发生内存泄漏
观察者会绑定到 Lifecycle
对象,并在其关联的生命周期遭到销毁后进行自我清理。
不会因 Activity 中止而致使崩溃
若是观察者的生命周期处于非活跃状态
(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
自动判断生命周期并回调方法
若是观察者的生命周期处于 STARTED
或 RESUMED
状态,则 LiveData 会认为该观察者处于活跃状态,就会调用onActive
方法,不然,若是 LiveData 对象没有任何活跃观察者时,会调用 onInactive()
方法。
说到原理,其实就是两个方法:
observe
方法。经过该方法把订阅者和被观察者关联起来,造成观察者模式。简单看看源码:
@MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); //... LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && !existing.isAttachedTo(owner)) { throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } if (existing != null) { return; } owner.getLifecycle().addObserver(wrapper); } public V putIfAbsent(@NonNull K key, @NonNull V v) { Entry<K, V> entry = get(key); if (entry != null) { return entry.mValue; } put(key, v); return null; }
这里putIfAbsent
方法是讲生命周期相关的wrapper
和观察者observer
做为key和value存到了mObservers
中。
onChanged
方法。经过改变存储值,来通知到观察者也就是调用onChanged
方法。从改变存储值方法setValue
看起:@MainThread protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null); } private void dispatchingValue(@Nullable ObserverWrapper initiator) { //... do { mDispatchInvalidated = false; if (initiator != null) { considerNotify(initiator); initiator = null; } else { for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; } private void considerNotify(ObserverWrapper observer) { if (!observer.mActive) { return; } // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet. // // we still first check observer.active to keep it as the entrance for events. So even if // the observer moved to an active state, if we've not received that event, we better not // notify for a more predictable notification order. if (!observer.shouldBeActive()) { observer.activeStateChanged(false); return; } if (observer.mLastVersion >= mVersion) { return; } observer.mLastVersion = mVersion; //noinspection unchecked observer.mObserver.onChanged((T) mData); }
这一套下来逻辑仍是比较简单的,遍历刚才的map——mObservers
,而后找到观察者observer
,若是观察者不在活跃状态(活跃状态,也就是可见状态,处于 STARTED 或 RESUMED状态),则直接返回,不去通知。不然正常通知到观察者的onChanged方法。
固然,若是想任什么时候候都能监听到,都能获取回调,调用observeForever
方法便可。
有一块儿学习的小伙伴能够关注下❤️个人公众号——码上积木,天天三问面试真题,详细剖析,助你成为offer收割机。