最近簡單看了下google推出的框架Jetpack,感受此框架的內容能夠對平時的開發有很大的幫助,也能夠解決不少開發中的問題,對代碼的邏輯和UI界面實現深層解耦,打造數據驅動型UI界面。java
Android Architecture組件是Android Jetpack的一部分,它們是一組庫,旨在幫助開發者設計健壯、可測試和可維護的應用程序,包含一下組件:bash
上述時Android Architecture所提供的架構組件,本文主要從使用和源碼的角度瞭解一下ViewModel組件的機制架構
Android框架管理UI控制器的生命週期,例如活動和片斷。框架能夠決定銷燬或從新建立UI控制器以響應徹底不受您控制的某些用戶動做或設備事件,那設想一種狀況當用戶在界面操做錄入了一些信息後,由於某種緣由致使Activity從新建立,那此時用戶寫好的信息呢?若是要重頭再來可能有的用戶就會不耐煩了,進而減小了使用。。。,可能有人說,可使用該 onSaveInstanceState()方法並從包中恢復其數據 onCreate(),但此方法僅適用於能夠序列化而後反序列化的少許數據,若是要恢復的數據量比較大,此時就時VIewModel的厲害之處了。併發
ViewModel之因此能在Activity重建時保存並恢復數據,由於Activity初次建立時會初始化建立VIewModel,在Activity銷燬時,ViewModel對象不會銷燬,在新的Activity從新建立後,仍然會執行以前的獲取ViewModel的過程,Android系統採起了處理機制,使如今拿到的ViewModel就是前一次建立的對象,設想一下數據都儲存在VIewModel中,而兩次拿到的都是同一個VIewModel,那顯示的數據天然就和以前的同樣嘍,這裏先放一張系統處理ViewModel的建立、存儲和獲取流程圖:app
class Model : ViewModel() {
var textName = "Empty"
}複製代碼
val model = ViewModelProviders.of(this)[Model::class.java]複製代碼
tvModel.text = model.textName複製代碼
btn_change.setOnClickListener {
model.textName = "Change = 22222"
tvModel.text = model.textName
}複製代碼
5.1 、ViewModelProviders.of(this)[Model::class.java]框架
從上面的方法中能夠看出ViewModel的獲取過程分爲兩步:ide
ViewModelProviders提供四個構造方法建立VIewProvider,兩個帶有factory兩個沒有,不過沒有factory的其實使用的是默認的Factory,因此四個方法基本一致只是Fragment和Activity的區分源碼分析
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment) {
return of(fragment, null);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
Application application = checkApplication(checkActivity(fragment));
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(ViewModelStores.of(fragment), factory);
}
@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(ViewModelStores.of(activity), factory);
}複製代碼
@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;
}複製代碼
上面的執行是,先去ViewModelStore中獲取,若是爲空就調用Factory的create()建立ViewModel,並儲存在VIewmoStore中,與咱們所想一致;post
5.2 、VIewModelStore測試
上述過程當中使用ViewModelStore.of(this) 建立ViewModelStore,方法源碼:
@NonNull
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}複製代碼
先判斷Activity是否爲 ViewModelStoreOwner,若是是直接獲取其中的ViewModelStore,不然調用holderFragmentFor(activity).getViewModelStore()獲取
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
// HolderFragmentManger
HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
HolderFragment holder = findHolderFragment(fm); // 根據TAG查找Fragment
if (holder != null) {
return holder;
}
holder = mNotCommittedActivityHolders.get(activity); // 從儲存的集合中獲取
if (holder != null) {
return holder;
}
if (!mActivityCallbacksIsAdded) {
mActivityCallbacksIsAdded = true;
activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
}
holder = createHolderFragment(fm); // 建立HolderFragment
mNotCommittedActivityHolders.put(activity, holder); // 保存到集合
return holder;
}複製代碼
private static HolderFragment findHolderFragment(FragmentManager manager) {
if (manager.isDestroyed()) {
throw new IllegalStateException("Can't access ViewModels from onDestroy");
}
// 根據TAG查找
Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
...
return (HolderFragment) fragmentByTag;
}
private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
HolderFragment holder = new HolderFragment();
fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss(); // 設置TAG
return holder;
}複製代碼
5.三、HolderFragment
上面的過程都是獲取或建立HolderFragment的過程,有沒有想過咱們要的是儲存ViewModel的地方,爲何一值在操做Fragment,答案就在其中:
public class HolderFragment extends Fragment implements ViewModelStoreOwner {
}複製代碼
private ViewModelStore mViewModelStore = new ViewModelStore();
@NonNull
@Override
public ViewModelStore getViewModelStore() {
return mViewModelStore;
}複製代碼
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);
}複製代碼
整個ViewModel的源碼分析到此結束了,總結一下內部的儲存邏輯
在上面獲取Fragment中時,建立過HolderFragment後保存在Map中,如今咱們看一下這個map
private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();複製代碼
Map的鍵就是Activity的實例,因此不管多少次建立都是此Activity的實例,也就得到惟一的一個對應的Fragment
按照上一個問題的邏輯,主要是傳入的Activity的對象一致,那獲取到就是同一個Fragment,存儲的也是同一個VIewStore,那設想一下,若是一個Activity中有多個Fragment,利用這個特性就能夠實現數據交互了;例如:兩個Fragment之間。一個顯示標題列表,點擊某一個標題,另外一個Fragment顯示內容,此時使用一個ViewModel實現二者的傳遞
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item); // 設置數據
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// Update the UI.
});
}
}複製代碼
到此ViewModel的介紹完成了,將ViewModel和LiveData或其餘組件聯合使用,構造數據驅動型的界面,相信必定會帶來不同的體驗。