最近一個月主要實現了IM功能,其中UI框架使用了ViewModel和LiveData的存儲和通知機制,實現後代碼簡潔易於維護。
感慨於Android arch components控件強大同時,須要順帶分析一波其中源碼實現。今天先來分析一下ViewModel的源碼實現。java
ViewModel是經過關聯生命週期的方式來存儲和管理跟UI相關的數據。即便configuration發生變化,在ViewModel中存放的數據是不會被銷燬的。
沒使用ViewModel的時候,若是系統Configuration發生變化,咱們的Activity會被銷燬重建,致使Activity中的UI數據丟失。爲了規避這個問題,咱們只能在onSaveInstanceState()將UI數據進行保存,在onCreate方法中判斷savedInstanceState中是否有咱們存儲的數據。
有了ViewModel以後,咱們只須要將數據存儲到ViewModel便可,ViewModel中的數據不會隨着Activity的銷燬重建而消失。同時,若是不一樣的Fragment使用相同的Activity對象來獲取ViewModel,能夠輕易的實現數據共享和通訊。app
使用ViewModel的例子:框架
// 自定義一個ViewModel,存儲一個字符串 public class TestViewModel extends ViewModel { public String content; @Override protected void onCleared() { // 數據清理工做 content = null; } } // 在Activity中獲取並使用ViewModel TestViewModel viewModel = ViewModelProviders.of(activity).get(TestViewModel.class); Log.d("tag", viewModel.content);
我我的習慣,看源碼時候老是要帶着問題去分析理解,這樣纔會有所收穫。ide
經過示例代碼,去掉鏈式調用後,咱們能夠看到ViewModel是經過以下兩步建立出來的:函數
// 1. 建立ViewModelProvider ViewModelProvider viewModelProvider = ViewModelProviders.of(activity); // 2. 經過反射獲取ViewModel TestViewModel viewModel = viewModelProvider.get(TestViewModel.class);
先看下第一步的源碼實現:源碼分析
public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) { if (factory == null) { // 若是傳入的對象建立工廠類爲null,則使用默認的AndroidViewModelFactory來建立對象 factory = AndroidViewModelFactory.getInstance(application); } // 建立一個ViewModelProvider return new ViewModelProvider(ViewModelStores.of(activity), (Factory)factory); }
源碼中,咱們發現建立一個ViewModelProvider須要傳入兩個參數:ViewModelStore和Factory。咱們先看下Factory的實現。學習
Factory顧名思義,定義了建立ViewModel的行爲接口。裏面只有一個create方法,用於子類自行決定如何實現一個ViewModel對象的建立。this
public interface Factory { <T extends ViewModel> T create(@NonNull Class<T> modelClass); }
同時,ViewModelProvider源碼內部也提供了兩個默認Factory實現:NewInstanceFactory和AndroidViewModelFactory。google
// 直接反射Class對象的無參構造函數來建立ViewModel public static class NewInstanceFactory implements Factory { @Override public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { try { return modelClass.newInstance(); } catch (InstantiationException e) { throw new RuntimeException("Cannot create an instance of " + modelClass, e); } catch (IllegalAccessException e) { throw new RuntimeException("Cannot create an instance of " + modelClass, e); } } } // 1. 若是對象繼承自AndroidViewModel,發射調用帶Application參數的構造函數建立ViewModel對象; // 2. 若是對象不繼承自AndroidViewModel,則直接調用父類,即調用Class的無參構造函數建立ViewModel對象。 public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory { private static AndroidViewModelFactory sInstance; @NonNull public static AndroidViewModelFactory getInstance(@NonNull Application application) { if (sInstance == null) { sInstance = new AndroidViewModelFactory(application); } return sInstance; } private Application mApplication; public AndroidViewModelFactory(@NonNull Application application) { mApplication = application; } @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對象若是構造函數中須要其餘各類參數,咱們只須要建立一個自定義的Factory類,而後調用該class的有參構造函數進行建立便可。spa
ViewModelStore就是個HashMap,經過key來獲取ViewModel對象。
public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap<>(); final void put(String key, ViewModel viewModel) { ViewModel oldViewModel = mMap.get(key); if (oldViewModel != null) { oldViewModel.onCleared(); } mMap.put(key, viewModel); } final ViewModel get(String key) { return mMap.get(key); } }
瞭解了Factory實現和ViewModelStore實現後,咱們來看一下ViewModelProvider的get方法是如何建立ViewModel對象的。
public class ViewModelProvider { private final Factory mFactory; private final ViewModelStore mViewModelStore; public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) { mFactory = factory; this.mViewModelStore = store; } public <T extends ViewModel> T get(@NonNull Class<T> modelClass) { String canonicalName = modelClass.getCanonicalName(); 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)) { return (T) viewModel; } viewModel = mFactory.create(modelClass); mViewModelStore.put(key, viewModel); //noinspection unchecked return (T) viewModel; } }
ViewModleProvider的get方法實現也比較簡單,總結一下就是:
至此,第一個問題ViewModel是如何建立出來的已經分析完畢。接下來,咱們看第二個問題。
講道理,若是同窗們仔細看了ViewModel的建立流程,這個問題天然迎刃而解。
由於不一樣的Fragment使用相同的Activity對象來獲取ViewModel,在建立ViewModel以前都會先從Activity提供的ViewModelStore中先查詢一遍是否已經存在該ViewModel對象。因此咱們只須要先在Activity中一樣調用一遍ViewModel的獲取代碼,便可讓ViewModel存在於ViewModelStore中,從而不一樣的Fragment能夠共享一份ViewModel了。
在看這個問題以前,咱們回到ViewModelProviders.of()源碼中:
public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) { if (factory == null) { // 若是傳入的對象建立工廠類爲null,則使用默認的AndroidViewModelFactory來建立對象 factory = AndroidViewModelFactory.getInstance(application); } // 建立一個ViewModelProvider return new ViewModelProvider(ViewModelStores.of(activity), (Factory)factory); }
ViewModelProvider獲取ViewModelStore是經過ViewModelStores.of(activity)實現的。咱們先看一下這個ViewModelStores作了什麼操做。
看名字又像是一個封裝好的工廠類。看下源碼:
public static ViewModelStore of(@NonNull FragmentActivity activity) { return activity instanceof ViewModelStoreOwner ? ((ViewModelStoreOwner)activity).getViewModelStore() : HolderFragment.holderFragmentFor(activity).getViewModelStore(); }
經過源碼能夠發現,若是Activity是ViewModelStoreOwner的實現類,則直接經過activity獲取ViewModelStore,若是不是,則經過HolderFragment.holderFragmentFor(activity).getViewModelStore()來獲取。
經過查看FragmentActivity源碼,發現其已是實現了ViewModelStoreOwner接口。
public class FragmentActivity extends BaseFragmentActivityApi16 implements ViewModelStoreOwner, ActivityCompat.OnRequestPermissionsResultCallback, ActivityCompat.RequestPermissionsRequestCodeValidator { }
因此這裏咱們已經不須要理會HolderFragment了,不少分析ViewModel源碼的文章都會花不少篇幅分析HolderFragment,我實在是搞不懂爲何要這種操做。(初步懷疑是互相抄襲。。.)
雖然FragmentActivity實現了ViewModelStoreOwner接口,可以提供ViewModelStore,可是ViewModelStore是如何跟Activity生命週期關聯起來的呢?
搜索了一下FragmentActivity中關於ViewModelStore的調用,發現這裏的實現應該跟生命週期處理有關。
google搜索了一下Activity的onRetainNonConfigurationInstance的做用:大部分同窗知道Activity由於configuration變化銷燬和重建時會調用onSaveInstanceState和onRestoreInstanceState。與此同時,Activity其實還會回調onRetainNonConfigurationInstance和getLastNonConfigurationInstance方法。
onRetainNonConfigurationInstance和onSaveInstanceState做用相同,用來保存UI相關變量,當Activity意外銷燬時,Activity的ViewModelStore對象就是在這裏進行了保存。
那什麼時機進行的恢復呢?
當Activity的onCreate調用時,會調用getLastNonConfigurationInstance,獲取以前保存的ViewModelStore,若是ViewModelStore不爲空,就進行賦值。這裏進行了ViewModelStore的恢復。
這裏咱們又學到了Activity的兩個跟生命週期相關的函數調用:onRetainNonConfigurationInstance和getLastNonConfigurationInstance。
三個問題分析完畢,相信你們已經對ViewModel的實現原理比較熟悉了。建議你們之後學習源碼時,也帶着問題去分析思考,事半功倍。