1. MVVM 架構詳細介紹及源碼層面理解
整體架構
MVVM(Model - 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 實例化方法及源碼分析
實例化方法
- MutableLiveData:
MutableLiveData
?是?LiveData
?的子類,它公開了?setValue()
?和?postValue()
?方法,允許外部修改其持有的數據。
MutableLiveData<String> liveData = new MutableLiveData<>();
在源碼中,MutableLiveData
?只是簡單地繼承了?LiveData
?并暴露了修改數據的方法。
public class MutableLiveData<T> extends LiveData<T> {@Overridepublic void postValue(T value) {super.postValue(value);}@Overridepublic void setValue(T value) {super.setValue(value);}
}
- 使用?
Transformations
?類進行轉換:Transformations
?類提供了一些靜態方法,如?map()
?和?switchMap()
,可以對 LiveData 進行轉換。
LiveData<Integer> source = new MutableLiveData<>();
LiveData<String> transformed = Transformations.map(source, input -> "Transformed: " + input);
map()
?方法的源碼實現如下:
public static <X, Y> LiveData<Y> map(LiveData<X> source,final Function<X, Y> mapFunction) {final MediatorLiveData<Y> result = new MediatorLiveData<>();result.addSource(source, new Observer<X>() {@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 (Iterator<Map.Entry<Observer<? 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 NonStickyLiveData<T> extends LiveData<T> {private final AtomicBoolean mPending = new AtomicBoolean(false);@Overridepublic void observeForever(@NonNull Observer<? super T> observer) {super.observeForever(new Observer<T>() {@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 Observer<T>() {@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
?類中,通過標記數據是否已被處理來避免重復觸發。在觀察者獲取數據時,先檢查標記位,若未處理則處理數據并設置標記位,防止重復處理粘性數據。 - 使用?
MediatorLiveData
:MediatorLiveData
?可監聽其他 LiveData 變化,并在必要時過濾粘性事件。通過添加源 LiveData 的觀察者,在數據變化時進行相應處理,如更新自身數據后移除源 LiveData,避免粘性事件傳遞給新觀察者。