本文涉及的源碼版本如下:
- com.android.support:appcompat-v7:27.1.1
- android.arch.lifecycle:extensions:1.1.1
- android.arch.lifecycle:viewmodel:1.1.1
- android.arch.lifecycle:livedata:1.1.1
什么是ViewModel, 以及工作原理
ViewModel用於存儲和管理UI相關的數據,ViewModel有自己生命周期,會根據fragment,activity的生命周期銷毀。當配置發生改變時, ViewModel存儲的數據還是存在的,不會被銷毀。(例如旋轉屏幕,旋轉屏幕通常會導致activity重建)
ViewModel 相關類結構

ViewModel:抽象類,onCleared方法用於釋放資源
AndroidViewModel: 繼承了ViewModel, 沒什么區別, 構造可以傳入一個application
ViewModelStore: ViewModel存儲器, 內部Map存儲
ViewModelStoreOwner: 一個接口, ViewModelStore擁有者。 Fragment和FragmentActivity實現了接口
Factory: 一個工廠接口,用於創建ViewModel。是ViewModelProvider的內部接口
NewInstanceFactory: 繼承Factory, 通過反射class.newInstance()產生一個ViewModel。所以使用這個Factory,ViewModel需要有空參構造器。
AndroidViewModelFactory: 繼承Factory, 也是通過反射產生一個AndroidViewModel, 而且這個AndroidViewModel構造器必須只有一個application參數, 如何反射創建失敗會調用NewInstanceFactory去創建。
ViewModelProvider: 是一個幫助類,構造器可以傳入ViewModelStore和Factory, 會根據Factory產生一個ViewModel, 並存儲到ViewModelStore里。
ViewModel的生命周期
ViewModel的生命周期是跟fragment, activity生命周期關聯的。只有fragment, activity銷毀時才會調用ViewModel.onCleared() (配置改成導致銷毀,不會調用onCleared)
ViewModel存儲在ViewModelStore, ViewModel的onCleared方法在ViewModelStore的clear方法時被調用, ViewModelStore源碼如下:
private final HashMap<String, ViewModel> mMap = new HashMap<>(); /** * 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(); } 復制代碼
下面看看Fragment, 和FragmentActivity的實現,先看Fragment的實現:
public ViewModelStore getViewModelStore() { if (getContext() == null) { throw new IllegalStateException("Can't access ViewModels from detached fragment"); } // new一個ViewModelStore, 一個Fragment只有一個ViewModelStore if (mViewModelStore == null) { mViewModelStore = new ViewModelStore(); } return mViewModelStore; } public void onDestroy() { mCalled = true; // Use mStateSaved instead of isStateSaved() since we're past onStop() if (mViewModelStore != null && !mHost.mFragmentManager.mStateSaved) { mViewModelStore.clear(); // mStateSaved用於判讀是否由於配置改變導致Fragment重建 } } 復制代碼
再看FragmentActivity的實現
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) { mViewModelStore = new ViewModelStore(); } return mViewModelStore; } protected void onDestroy() { super.onDestroy(); .... if (mViewModelStore != null && !mRetaining) { // mRetaining用於判讀是否由於配置改變導致Fragment重建 mViewModelStore.clear(); } } 復制代碼
ViewModel存儲的數據不會在配置改變時而銷毀, ViewModel是怎樣保存的呢,看前面的分析在Fragment, FragmentActivity都有一個mViewModelStore的成員變量,只要保存好這個mViewModelStore這個就可以啦。當配置改變時,在onSaveInstanceState里保存數據,然后在onRestoreInstanceState恢復數據,但是這兩個方法存儲數據只能放在Bundle, 只能存小量數據, 過大會拋TransactionTooLargeException異常。所以不合適,看源碼發現是利用Activity的onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()。
// FragmentActivity關鍵代碼 public final Object onRetainNonConfigurationInstance() { Object custom = onRetainCustomNonConfigurationInstance(); // 這方法繼承自Activty, 且把方法定義成final,不讓子類實現,但是提供onRetainCustomNonConfigurationInstance方法 FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig(); //fragments是當前activity所有fragment需要保存的數據 if (fragments == null && mViewModelStore == null && custom == null) { return null; } NonConfigurationInstances nci = new NonConfigurationInstances(); nci.custom = custom; nci.viewModelStore = mViewModelStore; nci.fragments = fragments; // mViewModelStore 和 fragments 就存在NonConfigurationInstances里 return nci; } protected void onCreate(@Nullable Bundle savedInstanceState) { ... NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); // 調用getLastNonConfigurationInstance方法獲取NonConfigurationInstances恢復數據 if (nc != null) { mViewModelStore = nc.viewModelStore; } if (savedInstanceState != null) { Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG); mFragments.restoreAllState(p, nc != null ? nc.fragments : null); //nc.fragments通過mFragments.restoreAllState()恢復 } ... } 復制代碼
這里onRetainNonConfigurationInstance和getLastNonConfigurationInstance方法就不深入啦,配置改變時還想保存一些自定義object數據可以重寫onRetainCustomNonConfigurationInstance去實現。那Fragment的mViewModelStore呢,就是mFragments.retainNestedNonConfig() 和 mFragments.restoreAllState() 這兩個方法啦。 mFragments是FragmentController實例,最后是調用到FragmentManager, 而FragmentManager真正實現是FragmentManagerImpl。下面截取部分FragmentManagerImpl的關鍵代碼。
// 這個方法就Activity里mFragments.retainNestedNonConfig()最終調用的方法 FragmentManagerNonConfig retainNonConfig() { setRetaining(mSavedNonConfig); // 由於篇幅的原因, 這個方法本文不展開了 return mSavedNonConfig; } //來看mSavedNonConfig這個實例是在哪里創建的,回到FragmentActivity.onSaveInstanceState方法里發現調用mFragments.saveAllState()保存狀態,最終來到FragmentManagerImpl的saveAllState() Parcelable saveAllState() { mSavedNonConfig = null; saveNonConfig(); } void saveNonConfig() { ArrayList<Fragment> fragments = null; ArrayList<FragmentManagerNonConfig> childFragments = null; ArrayList<ViewModelStore> viewModelStores = null; if (mActive != null) { //mActive是SparseArray<Fragment>, 代表fragment棧, 遍歷mActive, for (int i=0; i<mActive.size(); i++) { Fragment f = mActive.valueAt(i); if (f != null) { ... if (viewModelStores != null) { // 把fragment的成員變量mViewModelStore添加到list中 viewModelStores.add(f.mViewModelStore); } } } } if (fragments == null && childFragments == null && viewModelStores == null) { mSavedNonConfig = null; } else { //viewModelStores存儲到FragmentManagerNonConfig里 mSavedNonConfig = new FragmentManagerNonConfig(fragments, childFragments, viewModelStores); } } //mFragments.restoreAllState() 最終調用FragmentManagerImpl的restoreAllState() void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) { if (state == null) return; FragmentManagerState fms = (FragmentManagerState)state; //fms是保存狀態時存儲在Parcelable的,現在拿出來恢復狀態 if (fms.mActive == null) return; //這里有很多種情況,這里大概分析常見的恢復過程 ... mActive = new SparseArray<>(fms.mActive.length); //遍歷FragmentState for (int i=0; i<fms.mActive.length; i++) { FragmentState fs = fms.mActive[i]; if (fs != null) { ... ViewModelStore viewModelStore = null; if (viewModelStores != null && i < viewModelStores.size()) { viewModelStore = viewModelStores.get(i); } Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig, viewModelStore); // 傳入viewModelStore, 調用instantiate方法重新生成Fragment if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f); mActive.put(f.mIndex, f); } } } 復制代碼
什么是LiveData, 以及工作原理
LiveData是一個可觀察數據的持有者, 但是不像普通的可觀察數據, LiveData是綁定了生命周期,例如activitie, fragment的生命周期。有點抽象, 還是先了解一下關鍵的類。
//Observer是一個接口,觀察者。當數據改變時就回調onChanged public interface Observer<T> { void onChanged(@Nullable T t); } //LiveData類是個抽象類,這里先看看有什么暴露出去的方法 public abstract class LiveData<T> { //添加觀察者觀察, 傳入LifecycleOwner,用於來綁定生命周期 public void observe(LifecycleOwner owner, Observer<T> observer) //添加觀察者觀察, 但是是沒有LifecycleOwner public void observeForever(Observer<T> observer) //移除觀察者 public void removeObserver(Observer<T> observer) //移除某個LifecycleOwner里所有的觀察者 public void removeObservers(final LifecycleOwner owner) //是否有觀察者 public boolean hasObservers() //是否有活的觀察者 public boolean hasActiveObservers() } //MutableLiveData繼承LiveData, 多開放2個方法。 public class MutableLiveData<T> extends LiveData<T> { public void postValue(T value) //post一個數據 public void setValue(T value) //設置一個數據 //postValue和setValue的區別是:post可以在子線程用,而setValue只能在UI線程調用 } 復制代碼
介紹完了主要的類,下面舉個例子:
// 這段代碼通常在Activity或者Fragment中, 用liveData去添加一個觀察者
// AppCompatActivity或者Fragment已經LifecycleOwner,通常傳this即可
// 當User數據有變化時,onChanged方法會被調用, 用於更新UI
liveData.observe(this, new Observer<User>() {
@Override
public void onChanged(@Nullable User user) {
//更新UI
}
});
//下面這段代碼通常在ViewModel中,這里liveData和上面代碼的liveData是同一個
//可以通過postValue或者setValue去改成user數據, 有數據改變時, onChanged方法會被回調 //假如一個場景, 在ViewModel中,通過網絡請求去拿user數據,然后postValue就會去通知UI層onChanged去更新UI //liveData大概就是這個流程 liveData = new MutableLiveData<User>() liveData.postValue(user)// 或者setValue(user) 復制代碼
下面還是看看LiveData源碼去了解一下原理
LiveData工作原理
這里以observe(LifecycleOwner owner, Observer observer) 和 postValue之間數據的通訊為例分析。對LifecycleOwner不熟悉的可以看我的上一篇文章:LifecycleOwner, 下面看LiveData.observe源碼:
@MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) { //判斷當前生命周期是DESTROYED, 立馬return, 都銷毀了,添加觀察者沒意義 if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); //LifecycleBoundObserver繼承ObserverWrapper, LifecycleBoundObserver實現LifecycleOwner //mObservers這是一個Map, key是observer, value是ObserverWrapper 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和ObserverWrapper片段:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver { @NonNull final LifecycleOwner mOwner; @Override boolean shouldBeActive() { //至少是STARTED狀態 return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } //GenericLifecycleObserver繼承自LifecycleObserver, 當生命周期改變時onStateChanged會被回調 @Override public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) { //生命周期處於DESTROYED時, 移除觀察者,mObserver是livedata.observe時傳進來 if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { removeObserver(mObserver); return; } //shouldBeActive()方法實現在當前類, 調用isAtLeast(STARTED), 至少是STARTED狀態才是true //就是生命周期在STARTED和RESUME狀態時, 才是true //接着調用了父類的activeStateChanged activeStateChanged(shouldBeActive()); } } private abstract class ObserverWrapper { void activeStateChanged(boolean newActive) { // mActive狀態相同立即返回 if (newActive == mActive) { return; } // immediately set active state, so we'd never dispatch anything to inactive // owner mActive = newActive; //就是生命周期在STARTED和RESUME時, mActive為true, 其他為false boolean wasInactive = LiveData.this.mActiveCount == 0; LiveData.this.mActiveCount += mActive ? 1 : -1; //當mActive=true時, mActiveCount會加1, 當mActive=false時, mActiveCount會減1。 //這里為什么要加1和減1呢,結合Activity生命周期去考慮,當Activity.onCreate -> Activity.onStart -> Activity.onResume, State由CREATED->STARTED->RESUMED,這個過程當到STARTED時mActive為true,mActiveCount加1后為1, 接着RESUMED, mActive還是true, 這方法第一句(newActive == mActive)條件成立直接return, mActiveCount此時還是1。 //當Activity.onResume->Activity.onPause->Activity.onStop,State由RESUMED->STARTED->CREATED, Activity.onStop后State為CREATED, isAtLeast(STARTED)就為false, 此時mActive=false, mActiveCount減1,mActiveCount為0啦。 //當Activity.onStop->Activity.onStart->Activity.onResume, State由CREATED->STARTED->RESUMED, mActive為true,mActiveCount加1后為1, mActiveCount此時為1。 if (wasInactive && mActive) { //根據上面一大段分析后,onActive會在Activity首次顯示UI調用,從后台返回或者從另一個Activity回退后又調用一次。(打開透明Activity不走onStop,這種情況除外) onActive(); } if (LiveData.this.mActiveCount == 0 && !mActive) { // Activity.onStop后調用 onInactive(); } if (mActive) { //分發數據, 跟蹤dispatchingValue方法,會到LiveData.considerNotify方法 dispatchingValue(this); } } } private void considerNotify(ObserverWrapper observer) { if (!observer.mActive) { //mActive可以知道是否處於onStop狀態, 是Stop狀態就不要分發數據 return; } if (!observer.shouldBeActive()) { //shouldBeActive()再次檢查是否observer活着 //ObserverWrapper的實現類不止LifecycleBoundObserver, 這里暫時沒看懂為什么再次檢查 observer.activeStateChanged(false); return; } if (observer.mLastVersion >= mVersion) { //mVersion會在調用postValue()或者setValue()處+1 return; } observer.mLastVersion = mVersion; observer.mObserver.onChanged((T) mData); 調用onChanged分發改變的數據 } 復制代碼
接着看postValue方法是是如果把值傳到onChanged里:
protected void postValue(T value) { boolean postTask; synchronized (mDataLock) { // 一開始看到這里有點疑問,1. 為什么加鎖, 1. 為什么要一個NOT_SET變量(NOT_SET是一個Obj對象) // 先帶着疑問往下看 postTask = mPendingData == NOT_SET; mPendingData = value; } if (!postTask) { // 先往下看,和加鎖問題一起解釋 return; } ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); // mPostValueRunnable運行在主線程 } private final Runnable mPostValueRunnable = new Runnable() { @Override public void run() { Object newValue; synchronized (mDataLock) { //加鎖, 和postValue里的鎖是一樣的 newValue = mPendingData; mPendingData = NOT_SET; } setValue((T) newValue); } }; @MainThread protected void setValue(T value) { assertMainThread("setValue"); mVersion++; // 版本號加1,保證mVersion>mLastVersion mData = value; // 賦值給mData, 數據會分發到mObserver.onChanged dispatchingValue(null); //到這里很清晰啦,現在回頭看看postValue和mPostValueRunnable里的鎖,和NOT_SET的作用 //1. postValue方法可能會被很多條線程調用 //2. mPostValueRunnable異步運行在主線程, 主線程是串聯執行的,一次執行一個runnable //3. 不加鎖很明顯不行, 多線程調用時, value從postValue方法賦值給mPendingData, //在mPostValueRunnable主線程里把mPendingData賦值給mData, //mPendingData和mData都是指向同一個對象, mData在主線程都是指向了最新的對象。 //在主線程隊列的里mPostValueRunnable每次運行都是拿了最新的數據,有點多余 //4. 假如去掉NOT_SET, value從postValue方法賦值給mPendingData, // 再到setValue的mData, mPendingData和mData都是指向同一個對象, // 雖然加了鎖也沒用。但有了NOT_SET就不同啦, mPendingData地址給mData,NOT_SET地址給mPendingData, // 在postValue方法的子線程里新進來的value地址又賦值給mPendingData。 //5.看回postValue方法里 if (!postTask) { return } 這個地方, // 假如A線程調用了postValue, 把value賦值給mPendingData並釋放了鎖, // 把A.mPostValueRunnable放到主線程的Message中, // 但這時之前的B.mPostValueRunnable還沒運行完,運行到setValue方法,也沒有持有鎖。 // 這時B線程也調用了postValue, 這時A.mPostValueRunnable還沒運行,沒有把mPendingData=NOT_SET, // B線程postTask就為false了, 接着又把value賦值給mPendingData, 接着就直接return。 // 等A.mPostValueRunnable運行時, mPendingData又被B線程更新啦。 // if (!postTask) { return } 這個判斷能減少主線程沒必要mPostValueRunnable運行, // 而且能更新到最新的數據。 } private void dispatchingValue(@Nullable ObserverWrapper initiator) { // initiator是null , 下面是遍歷mObservers存儲ObserverWrapper通知所有觀察者 ... for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); // considerNotify前面分析過了,看回LiveData.observe的過程, 最終分發數據Observer.onChanged } } 復制代碼
ViewModel和LiveData結合使用
先說說使用ViewModel和LiveData時注意事項:
- ViewModel不要持有生命周期的對象,例如activity, fragment。最好context也不要持有
- 可以使用AndroidViewModel具有application對象
- activity, fragment不要擁有LiveData對象,LiveData最好保存在ViewModel里,ViewModel不會由於配置改變而銷毀
- activity, fragment也不要擁有數據對象,在Observer.onChange更新UI時,不要把數據存在activity, fragment中
public class UserActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
findViewById(R.id.btn_logout).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mViewModel.onLogout(); // 點擊按鈕退出登錄 } }); mViewModel = ViewModelProviders.of(this).get(UserViewModel.class); //ViewModelProviders是一個工具類,默認包含AndroidViewModelFactory把UserViewModel.class通過反射創建ViewModel並存儲在Activity中 mViewModel.getUserLiveData().observe(this, new Observer<User>() { @Override public void onChanged(@Nullable User user) { //在觀察者中更新UI if(user != null){ mTvName.setText(user.name); }else { //沒有登錄的狀態 mTvName.setText("用戶還沒登錄!!!!!"); } } }); mViewModel.loadUserInfo(); } } public class UserViewModel extends ViewModel { //userLiveData存儲在UserViewModel private final MutableLiveData<User> userLiveData = new MutableLiveData<User>(); public MutableLiveData<User> getUserLiveData() { return userLiveData; } @Override protected void onCleared() { //釋放資源 } public void loadUserInfo() { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException ignored) { } //開啟一個線程,異步操作,建議使用線程池,這里演示就直接new Thread User user = new User(); user.name = "Albert"; userLiveData.postValue(user); // 通知數據觀察者 } }).start(); } public void onLogout() { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException ignored) { } /開啟一個線程,異步操作 userLiveData.postValue(null); // 通知數據觀察者 } }).start(); } } 復制代碼
介紹完例子,下面說說優點:
- 數據更新通知UI更新,數據的更新關聯了生命周期,可以避免onStop時去更新UI.
- 不需要手動處理生命周期
- 沒有內存泄漏
- 配置更改,之前加載數據還能使用
- 可以共享資源, 主要體現在同一個Activity里fragments可以共享viewmodel,livedata等(這里不展開,后面有空再分享)
參考: