深圳办公室设计公司排名,网站关键词优化有用吗,网站建设宣传ppt模板下载,wordpress中文链接4041. MVVM 架构详细介绍及源码层面理解
整体架构
MVVM#xff08;Model - View - ViewModel#xff09;架构是为了解决视图和数据模型之间的耦合问题而设计的。它通过引入 ViewModel 作为中间层#xff0c;实现了视图和数据的分离#xff0c;提高了代码的可维护性和可测试性…1. MVVM 架构详细介绍及源码层面理解
整体架构
MVVMModel - View - ViewModel架构是为了解决视图和数据模型之间的耦合问题而设计的。它通过引入 ViewModel 作为中间层实现了视图和数据的分离提高了代码的可维护性和可测试性。
View视图层在 Android 中View 主要关联 Activity、Fragment 以及 XML 布局文件等负责呈现界面与响应用户交互。像 Activity 里设置布局、初始化视图元素以及处理用户点击等操作都属于 View 范畴。例如在一个登录界面 Activity 里布局文件定义了输入框、按钮等 UI 元素的样式与位置Activity 则处理按钮点击事件这些都在 View 层完成。Model数据模型层负责数据的获取、存储与处理。比如从网络请求用户信息、将数据存储到本地数据库等。在电商应用中从服务器获取商品列表数据或是将用户的购物车信息保存到本地数据库都由 Model 层执行。ViewModel视图模型层作为连接 View 与 Model 的纽带承担关键的界面显示逻辑处理任务。它从 Model 获取数据并将其转换为适合 View 展示的形式。例如在新闻应用中Model 获取到原始新闻数据列表ViewModel 可对数据进行加工如截取新闻摘要、处理图片链接等让数据能更好地在 View 中展示。在数据更新时ViewModel 通过 LiveData 等机制通知 View 进行相应更新。从源码层面看ViewModel 借助 ViewModelProvider 来创建与管理。ViewModelProvider 内部运用 ViewModelStore 存储 ViewModel 实例确保配置变更如屏幕旋转时ViewModel 实例不会被销毁维持数据的稳定性。
观察者模式在 MVVM 中的应用
在 MVVM 架构里观察者模式发挥着核心作用。ViewModel 持有数据以 LiveData 为例View 作为观察者监听 LiveData 数据变化。LiveData 内部维护了观察者列表当数据变更时会调用 dispatchingValue 方法遍历观察者列表。在 considerNotify 方法中判断观察者状态若活跃则通过 observer.mObserver.onChanged((T) mData) 通知观察者View 接收到通知后更新界面实现了 View 与 ViewModel 低耦合通信这在诸多面试真题里都有涉及是理解 MVVM 架构的关键。ViewModel 是通过 ViewModelProvider 来创建和管理的。
2. LiveData 实例化方法及源码分析
实例化方法
MutableLiveDataMutableLiveData 是 LiveData 的子类它公开了 setValue() 和 postValue() 方法允许外部修改其持有的数据。
MutableLiveDataString liveData new MutableLiveData();在源码中MutableLiveData 只是简单地继承了 LiveData 并暴露了修改数据的方法。
public class MutableLiveDataT extends LiveDataT {Overridepublic void postValue(T value) {super.postValue(value);}Overridepublic void setValue(T value) {super.setValue(value);}
}使用 Transformations 类进行转换Transformations 类提供了一些静态方法如 map() 和 switchMap()可以对 LiveData 进行转换。
LiveDataInteger source new MutableLiveData();
LiveDataString transformed Transformations.map(source, input - Transformed: input);map() 方法的源码实现如下
public static X, Y LiveDataY map(LiveDataX source,final FunctionX, Y mapFunction) {final MediatorLiveDataY result new MediatorLiveData();result.addSource(source, new ObserverX() {Overridepublic void onChanged(Nullable X x) {result.setValue(mapFunction.apply(x));}});return result;
}3. LiveData 如何实现生命周期绑定问题
LiveData 生命周期绑定机制在面试中频繁被问到其实现依赖于 Android 的 Lifecycle 组件。 当调用 LiveData.observe() 方法时会创建 LifecycleBoundObserver 对象它实现了 LifecycleEventObserver 接口来监听 LifecycleOwner如 Activity、Fragment的生命周期变化。在 observe() 方法源码中先检查 LifecycleOwner 状态若已销毁则直接返回否则创建 LifecycleBoundObserver 并添加到观察者列表同时将其注册到 LifecycleOwner 的生命周期观察者中。
public void observe(NonNull LifecycleOwner owner, NonNull Observer? super T observer) {assertMainThread(observe);if (owner.getLifecycle().getCurrentState() DESTROYED) {return;}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);
}LifecycleBoundObserver 的 onStateChanged 方法会在 LifecycleOwner 生命周期状态变化时被调用。在此方法中根据生命周期状态决定是否更新观察者。当状态变为 DESTROYED 时从 LiveData 的观察者列表移除该观察者防止内存泄漏当状态为 STARTED 或 RESUMED 时认为观察者活跃可接收数据更新。
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {NonNullfinal LifecycleOwner mOwner;LifecycleBoundObserver(NonNull LifecycleOwner owner, Observer? super T observer) {super(observer);mOwner owner;}Overrideboolean shouldBeActive() {return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);}Overridepublic void onStateChanged(NonNull LifecycleOwner source,NonNull Lifecycle.Event event) {if (mOwner.getLifecycle().getCurrentState() DESTROYED) {removeObserver(mObserver);return;}activeStateChanged(shouldBeActive());}Overrideboolean isAttachedTo(LifecycleOwner owner) {return mOwner owner;}Overridevoid detachObserver() {mOwner.getLifecycle().removeObserver(this);}
}这种机制确保 LiveData 仅在 LifecycleOwner 处于活跃状态STARTED 或 RESUMED时更新观察者有效避免内存泄漏与空指针异常是 LiveData 的重要特性。
4. LiveData 粘性事件的深入分析
粘性事件的概念
粘性事件是指当一个观察者注册到 LiveData 时即使该 LiveData 在观察者注册之前已经有了更新观察者仍然会接收到这些之前的更新。这是因为 LiveData 会记录最新的值当有新的观察者注册时会立即将最新的值发送给它。
源码层面分析
在 LiveData 的 observe() 方法中当新的观察者注册时会调用 dispatchingValue() 方法该方法会检查观察者的状态并将最新的值发送给它。
private void dispatchingValue(Nullable ObserverWrapper initiator) {if (mDispatchingValue) {mDispatchInvalidated true;return;}mDispatchingValue true;do {mDispatchInvalidated false;if (initiator ! null) {considerNotify(initiator);initiator null;} else {for (IteratorMap.EntryObserver? super 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;}if (!observer.shouldBeActive()) {observer.activeStateChanged(false);return;}if (observer.mLastVersion mVersion) {return;}observer.mLastVersion mVersion;// 调用观察者的 onChanged 方法发送最新的值observer.mObserver.onChanged((T) mData);
}在 considerNotify() 方法中会比较观察者的 mLastVersion 和 LiveData 的 mVersion如果 mLastVersion 小于 mVersion则会调用观察者的 onChanged() 方法将最新的值发送给它。
解决粘性事件的方法
为了避免粘性事件的影响可以考虑使用一些第三方库如 SingleLiveEvent 或自定义 LiveData 实现。以下是一个简单的自定义 LiveData 实现用于避免粘性事件
import androidx.lifecycle.LiveData;import java.util.concurrent.atomic.AtomicBoolean;public class NonStickyLiveDataT extends LiveDataT {private final AtomicBoolean mPending new AtomicBoolean(false);Overridepublic void observeForever(NonNull Observer? super T observer) {super.observeForever(new ObserverT() {Overridepublic void onChanged(T t) {if (mPending.compareAndSet(true, false)) {observer.onChanged(t);}}});}Overridepublic void observe(NonNull LifecycleOwner owner, NonNull Observer? super T observer) {super.observe(owner, new ObserverT() {Overridepublic void onChanged(T t) {if (mPending.compareAndSet(true, false)) {observer.onChanged(t);}}});}Overrideprotected void setValue(T value) {mPending.set(true);super.setValue(value);}Overrideprotected void postValue(T value) {mPending.set(true);super.postValue(value);}
}在这个自定义的 LiveData 中使用 AtomicBoolean 来标记是否有新的值需要发送只有当 mPending 为 true 时才会调用观察者的 onChanged() 方法从而避免了粘性事件的影响。
粘性事件总结 在 LiveData 机制里不活跃观察者对应 LifecycleOwner 处于 STOPPED 或 PAUSED 状态正常情况下不会接收数据更新事件。只有当观察者再次变为活跃状态时LiveData 才会将最新数据发送给它。这是因为在 LifecycleBoundObserver 的 shouldBeActive 方法中依据 LifecycleOwner 的当前生命周期状态判断观察者是否活跃不活跃则不进行数据分发。 然而LiveData 存在粘性事件问题这在面试中常被提及。粘性事件指新观察者注册时即便 LiveData 之前已有更新观察者仍会收到这些之前的更新数据。从源码层面分析在 LiveData 的 observe() 方法中新观察者注册后会调用 dispatchingValue() 方法。在 dispatchingValue() 内部的 considerNotify() 方法里通过比较观察者的 mLastVersion 和 LiveData 的 mVersion 来决定是否通知观察者。若 mLastVersion 小于 mVersion则调用观察者的 onChanged() 方法发送最新数据导致粘性事件发生。
为解决粘性事件问题常见方法如下
使用 SingleLiveEvent自定义一个继承自 MutableLiveData 的类重写相关方法确保事件只被消费一次。例如在一些开源项目中SingleLiveEvent 类通过设置标志位在 observe() 方法中判断标志位仅在首次观察时触发数据更新后续不再响应之前的粘性数据。使用 Event 包装类将数据包装在 Event 类中通过标记数据是否已被处理来避免重复触发。在观察者获取数据时先检查标记位若未处理则处理数据并设置标记位防止重复处理粘性数据。使用 MediatorLiveDataMediatorLiveData 可监听其他 LiveData 变化并在必要时过滤粘性事件。通过添加源 LiveData 的观察者在数据变化时进行相应处理如更新自身数据后移除源 LiveData避免粘性事件传递给新观察者。