本文基于SDK 29
一、ViewModel與LiveData的作用:
1、viewModel:
資料共享,螢屏旋轉不丟失資料,并且在Activity與Fragment之間共享資料,
2、LiveData:
感知生命周期并且通知觀察者重繪,防止記憶體泄漏,
二、用法
三、原理:
1、ViewModel:
ViewModelProviders.of(this).get(MyViewModel::class.java)
我們通過這個方法來構造ViewModel,
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
/**
* Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given Activity
* is alive. More detailed explanation is in {@link ViewModel}.
* <p>
* It uses the given {@link Factory} to instantiate new ViewModels.
*
* @param activity an activity, in whose scope ViewModels should be retained
* @param factory a {@code Factory} to instantiate new ViewModels
* @return a ViewModelProvider instance
*/
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
從原始碼中可以看出,ViewModelProviders.of(this)獲取了一個ViewModelProvider 物件,而該物件中持有一個ViewModelProvider.AndroidViewModelFactory(因為我們傳進入的是null)
和activity.getViewModelStore(),
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
this.mViewModelStore = store;
}
我們再來看看ViewModelStore這個類,從名字中已經可以看出它的用途,那便是存盤ViewModel,
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
final ViewModel get(String key) {
return mMap.get(key);
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
我們的ViewModel便是存盤在上面的HashMap中,
接下來我們再來看ViewModelProviders.of(this).get(MyViewModel::class.java)的get方法:
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
可以看出,所以會去存盤ViewModel的ViewModelStore中拿,發現已經有了便直接回傳,如果沒有的話,那邊使用mFactory工廠進行構建,然后再放進ViewModelStore中,
從之前的分析可以看出,這里的mFactory便是AndroidViewModelFactory,
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
return super.create(modelClass);
}
其實該工廠也只是直接實體出該類而已,
此時我們便已經拿到了ViewModel,
可是它是怎么做到資料共享的呢,想做到資料共享,按理說它應該只有一個實體物件,我們且看,
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
在獲取ViewModelProvider的時候傳進去了activity.getViewModelStore(),那我們看一下activity.getViewModelStore()是怎么獲取ViewModelStore的,
@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.")
}
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
關鍵的代碼在于這一句:NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
FragmentManagerNonConfig fragments;
ArrayMap<String, LoaderManager> loaders;
VoiceInteractor voiceInteractor;
}
/* package */ NonConfigurationInstances mLastNonConfigurationInstances;
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
將mLastNonConfigurationInstances.activity強轉成FragmentActivity中的一個類:NonConfigurationInstances,然后獲取ViewModelStore
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
FragmentManagerNonConfig fragments;
}
NonConfigurationInstances是個靜態類,所以里面的ViewModelStore 也是唯一的,因此ViewModelStore 能做到資料共享,
2、LivaData
我們先看這個陳述句:
viewModel?.livaData?.observe(this, Observer<Int> { integer -> Log.d("MainActivity", integer!!.toString()) })
從這個陳述句往原始碼里面探究:
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
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);
}
如果這個activity處于銷毀狀態,那么便不會添加該觀察者,否則,構造一個LifecycleBoundObserver物件,放進mObservers里面,mObservers即為:
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
然后將LifecycleBoundObserver物件放進LifecycleRegistry里面,
LifecycleBoundObserver里面持有的物件如下:

當我們給LiveData設定值的時候:livaData.value = https://www.cnblogs.com/tangZH/p/i
public class MutableLiveData<T> extends LiveData<T> {
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
里面還有個postValue方法:
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData =https://www.cnblogs.com/tangZH/p/= NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
postValue最終也會呼叫到主執行緒,postValue可以在子執行緒呼叫,而setValue必須在主執行緒呼叫,否則會拋出例外,
我們看setValue方法:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
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;
}
這里我們傳進來的initiator為null,所以我們主要看:
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
這里的mObservers即為:
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
里面存放著我們之前放進去的LifecycleBoundObserver物件,
iterator.next().getValue()獲取的便是LifecycleBoundObserver物件,
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);
}
檢測當前生命周期,至少是處于start,
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
然后執行observer.mObserver.onChanged((T) mData);回呼出去,
observer.mObserver便是我們傳進去的觀察者:
Observer<Int> { integer -> Log.d("MainActivity", integer!!.toString()) }
由以上也可以看出:我們是可以注冊多個觀察者的,所以要注意在一個Activity中只能夠注冊一次,否則會發生多個回呼,
那么有個疑問,我們這樣已經實作了,那問什么在liveData?.observe方法里面,不但將LifecycleBoundObserver放進LiveData的SafeIterableMap里面,還要將其放入LifecycleRegistry
里面,owner.getLifecycle()獲取到的便是LifecycleRegistry

這是為了在相關的生命周期內做相關的操作,根據上一篇文章,我們可以知道,當activity的生命周期發生改變的時候,會獲取添加進LifecycleRegistry的觀察者,然后對每個觀察者進行回呼處理,
而在這里便會回呼LifecycleBoundObserver的onStateChanged方法,
@Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { removeObserver(mObserver); return; } activeStateChanged(shouldBeActive()); }
判斷如果當前處于DESTROYED狀態,那么便將我們添加進入的觀察者移除,
否則會呼叫activeStateChanged(shouldBeActive())方法,

如果當前的活躍狀態與上一次一樣,那么就直接回傳,
否則如果變為活躍的狀態,那么會呼叫dispatchingValue(this);

這里要注意,我們之前呼叫LiveData的setValue的時候,走的的2,但是現在走的是1,因為這次傳進來的引數不為空,
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; observer.mObserver.onChanged((T) mData); }
然后進入considerNotify這個方法,里面有一個判斷十分重要:
if (observer.mLastVersion >= mVersion) { return; }
這個判斷是做什么用的呢?mVersion是什么時候被賦值的,這時候就要我們回過去頭去看LiveData的setValue方法:

每呼叫一次,那么這個mVersion就會自加一,
所以這個判斷便保證了,必須是重繪了LiveData里面的data值,才能夠回呼觀察者事件:observer.mObserver.onChanged((T) mData);
如果生命周期變化的時候,LiveData里面的data值沒有重繪,就不能回呼出去,所以如果重繪LiveData里面的值的時候不處于活躍狀態導致沒有回呼,當生命周期來到onStart的時候就會去回呼,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/426472.html
標籤:Android
