经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Android » 查看文章
ViewModel和LiveData问题思考与解答
来源:cnblogs  作者:jimuzz  时间:2020/11/9 15:13:45  对本文有异议

嗨,大家好,面试真题系列又来了,今天我们说说MVVM架构里的两大组件:ViewModel和LiveData。
还是老样子,提出问题,做出解答。

  • ViewModel 是什么?

  • ViewModel 为什么被设计出来,解决了什么问题?

  • 说说ViewModel原理。

  • LiveData 是什么?

  • LiveData 为什么被设计出来,解决了什么问题?

  • 说说LiveData原理。

ViewModel 是什么,说说你所理解的ViewModel?

如果看过我上一篇文章的小伙伴应该都有所了解,ViewModel是MVVM架构的一个层级,用来联系View和model之间的关系。而我们今天要说的就是官方出的一个框架——ViewModel

ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据

官方是这么介绍的,这里面有两个信息:

  • 注重生命周期的方式。
    由于ViewModel的生命周期是作用于整个Activity的,所以就节省了一些关于状态维护的工作,最明显的就是对于屏幕旋转这种情况,以前对数据进行保存读取,而ViewModel则不需要,他可以自动保留数据。

其次,由于ViewModel在生命周期内会保持局部单例,所以可以更方便Activity的多个Fragment之间通信,因为他们能获取到同一个ViewModel实例,也就是数据状态可以共享了。

  • 存储和管理界面相关的数据。

ViewModel层的根本职责,就是负责维护界面上UI的状态,其实就是维护对应的数据,因为数据会最终体现到UI界面上。所以ViewModel层其实就是对界面相关的数据进行管理,存储等操作。

ViewModel 为什么被设计出来,解决了什么问题?

  • ViewModel组件被设计出来之前,MVVM又是怎么实现ViewModel这一层级的呢?

其实就是自己编写类,然后通过接口,内部依赖实现View和数据的双向绑定。
所以Google出这个ViewModel组件,无非就是为了规范MVVM架构的实现,并尽量让ViewModel这一层级只触及到业务代码,不去关心VIew层级的引用等。然后配合其他的组件,包括livedata,databindingrang等让MVVM架构更加完善,规范,健硕。

  • 解决了什么问题呢?

其实上面已经说过一些了,比如:

1)不会因为屏幕旋转而销毁,减少了维护状态的工作
2)由于在作用域内单一实例的特性,使得多个fragment之间可以方便通信,并且维护同一个数据状态。
3)完善了MVVM架构,使得解耦更加纯粹。

说说ViewModel原理。

  • 首先说说是怎么保存生命周期

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数据。一小段代码说明下:

  1. public <T extends ViewModel> T get(Class<T> modelClass) {
  2. // 先从ViewModelStore容器中去找是否存在ViewModel的实例
  3. ViewModel viewModel = mViewModelStore.get(key);
  4. // 若ViewModel已经存在,就直接返回
  5. if (modelClass.isInstance(viewModel)) {
  6. return (T) viewModel;
  7. }
  8. // 若不存在,再通过反射的方式实例化ViewModel,并存储进ViewModelStore
  9. viewModel = modelClass.getConstructor(Application.class).newInstance(mApplication);
  10. mViewModelStore.put(key, viewModel);
  11. return (T) viewModel;
  12. }
  13. public class ViewModelStore {
  14. private final HashMap<String, ViewModel> mMap = new HashMap<>();
  15. public final void clear() {
  16. for (ViewModel vm : mMap.values()) {
  17. vm.onCleared();
  18. }
  19. mMap.clear();
  20. }
  21. }
  22. @Override
  23. protected void onDestroy() {
  24. super.onDestroy();
  25. if (mViewModelStore != null && !isChangingConfigurations()) {
  26. mViewModelStore.clear();
  27. }
  28. }

LiveData 是什么?

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

官方介绍如下,其实说的比较清楚了,主要作用在两点:

  • 数据存储器类。也就是一个用来存储数据的类。

  • 可观察。这个数据存储类是可以观察的,也就是比一般的数据存储类多了这么一个功能,对于数据的变动能进行响应。

主要思想就是用到了观察者模式思想,让观察者和被观察者解耦,同时还能感知到数据的变化,所以一般被用到ViewModel中,ViewModel负责触发数据的更新,更新会通知到LiveData,然后LiveData再通知活跃状态的观察者。

  1. var liveData = MutableLiveData<String>()
  2. liveData.observe(this, object : Observer<String> {
  3. override fun onChanged(t: String?) {
  4. }
  5. })
  6. liveData.setVaile("xixi")
  7. //子线程调用
  8. liveData.postValue("test")

LiveData 为什么被设计出来,解决了什么问题?

LiveData作为一种观察者模式设计思想,常常被和Rxjava一起比较,观察者模式的最大好处就是事件发射的上游 和 接收事件的下游 互不干涉,大幅降低了互相持有的依赖关系所带来的强耦合性

其次,LiveData还能无缝衔接到MVVM架构中,主要体现在其可以感知到Activity等生命周期,这样就带来了很多好处:

  • 不会发生内存泄漏
    观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。

  • 不会因 Activity 停止而导致崩溃
    如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。

  • 自动判断生命周期并回调方法
    如果观察者的生命周期处于 STARTEDRESUMED状态,则 LiveData 会认为该观察者处于活跃状态,就会调用onActive方法,否则,如果 LiveData 对象没有任何活跃观察者时,会调用 onInactive()方法。

说说LiveData原理。

说到原理,其实就是两个方法:

  • 订阅方法,也就是observe方法。通过该方法把订阅者和被观察者关联起来,形成观察者模式。

简单看看源码:

  1. @MainThread
  2. public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
  3. assertMainThread("observe");
  4. //...
  5. LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
  6. ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
  7. if (existing != null && !existing.isAttachedTo(owner)) {
  8. throw new IllegalArgumentException("Cannot add the same observer"
  9. + " with different lifecycles");
  10. }
  11. if (existing != null) {
  12. return;
  13. }
  14. owner.getLifecycle().addObserver(wrapper);
  15. }
  16. public V putIfAbsent(@NonNull K key, @NonNull V v) {
  17. Entry<K, V> entry = get(key);
  18. if (entry != null) {
  19. return entry.mValue;
  20. }
  21. put(key, v);
  22. return null;
  23. }

这里putIfAbsent方法是讲生命周期相关的wrapper和观察者observer作为key和value存到了mObservers中。

  • 回调方法,也就是onChanged方法。通过改变存储值,来通知到观察者也就是调用onChanged方法。从改变存储值方法setValue看起:
  1. @MainThread
  2. protected void setValue(T value) {
  3. assertMainThread("setValue");
  4. mVersion++;
  5. mData = value;
  6. dispatchingValue(null);
  7. }
  8. private void dispatchingValue(@Nullable ObserverWrapper initiator) {
  9. //...
  10. do {
  11. mDispatchInvalidated = false;
  12. if (initiator != null) {
  13. considerNotify(initiator);
  14. initiator = null;
  15. } else {
  16. for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
  17. mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
  18. considerNotify(iterator.next().getValue());
  19. if (mDispatchInvalidated) {
  20. break;
  21. }
  22. }
  23. }
  24. } while (mDispatchInvalidated);
  25. mDispatchingValue = false;
  26. }
  27. private void considerNotify(ObserverWrapper observer) {
  28. if (!observer.mActive) {
  29. return;
  30. }
  31. // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
  32. //
  33. // we still first check observer.active to keep it as the entrance for events. So even if
  34. // the observer moved to an active state, if we've not received that event, we better not
  35. // notify for a more predictable notification order.
  36. if (!observer.shouldBeActive()) {
  37. observer.activeStateChanged(false);
  38. return;
  39. }
  40. if (observer.mLastVersion >= mVersion) {
  41. return;
  42. }
  43. observer.mLastVersion = mVersion;
  44. //noinspection unchecked
  45. observer.mObserver.onChanged((T) mData);
  46. }

这一套下来逻辑还是比较简单的,遍历刚才的map——mObservers,然后找到观察者observer,如果观察者不在活跃状态(活跃状态,也就是可见状态,处于 STARTED 或 RESUMED状态),则直接返回,不去通知。否则正常通知到观察者的onChanged方法。

当然,如果想任何时候都能监听到,都能获取回调,调用observeForever方法即可。

参考

viewmodel推荐阅读
livedata推荐阅读

拜拜

有一起学习的小伙伴可以关注下??我的公众号——码上积木,每天三问面试真题,详细剖析,助你成为offer收割机。

原文链接:http://www.cnblogs.com/jimuzz/p/13913179.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号