在說起Jetpack的ViewModel時,我們第一反應(yīng)都會想到它就是MVVM中的VM。然而這兩者并不是等價關(guān)系,Jetpack的ViewModel它只是官方為我們提供的一個具體工具,他的作用其實就是一個數(shù)據(jù)管理容器切油。而MVVM是一種構(gòu)架思想,VM是這里面的一層名惩,用來鏈接V與M層白翻。
由于Jetpack的ViewModel的獨有特性我們可以對它進(jìn)行拓展,使它充當(dāng)MVVM的VM角色。
1.ViewModel的使用
創(chuàng)建ViewModel
public class MyViewModel extends ViewModel {
public int count;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
獲取ViewModel對象
public class ViewModelActivity extends AppCompatActivity {
private MyViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
viewModel.setCount(2);
viewModel.getCount();
}
}
當(dāng)然上面的示例代碼沒有具體意義滤馍,但是純粹使用ViewModel就是這么簡單,先拋開ViewModel在MVVM中的使用底循,我們可以用ViewModel來做些什么呢巢株,它有怎樣的優(yōu)勢?
2.ViewModel的使用場景
2.1.橫豎屏切換時熙涤,Activity重新創(chuàng)建阁苞,可以通過ViewModel保存數(shù)據(jù)。
ViewModel與Activity生命周期關(guān)系如下:
可以看到祠挫,在屏幕旋轉(zhuǎn)Activity重新創(chuàng)建的過程中那槽,ViewModel一直保持存活。
2.2.同一個Activity下等舔,F(xiàn)ragment之間的數(shù)據(jù)共享骚灸。
我們可以將數(shù)據(jù)存放到Activity的ViewModel中,在Activity中的Fragment中通過以下代碼獲取到Activity中的ViewModel慌植,實現(xiàn)數(shù)據(jù)共享甚牲。
viewModel = ViewModelProviders.of(activity).get(MyViewModel.class);
3.ViewModel的實現(xiàn)原理
(下面的源碼分析都基于在Activity中使用ViewModel,旨在理清流程,在Fragmeng中的原理大致相同)
3.1.ViewModel的獲取
ViewModelProviders.of(activity).get(MyViewModel.class)
--ViewModelProviders.java
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);
}
這里需要注意activity.getViewModelStore()蝶柿,它是一個ViewModelStore對象丈钙,ViewModelStore的實現(xiàn)非常簡單,內(nèi)部維護(hù)一個HashMap用來存放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);
}
Set<String> keys() {
return new HashSet<>(mMap.keySet());
}
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
ViewModelProviders.of(activity)獲取到ViewModelProvider后雏赦,通過ViewModelProvider.get(modelClass)獲取ViewModel。
--ViewModelProvider.java
private static final String DEFAULT_KEY =
"androidx.lifecycle.ViewModelProvider.DefaultKey";
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);
}
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;
} else {
if (viewModel != null) {
}
}
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
這里的mViewModelStore就是上面new ViewModelProvider(activity.getViewModelStore(), factory)時傳入的activity的ViewModelStore芙扎。
整體流程:在獲取ViewModel時星岗,先從Acactivitytivity中的ViewModelStore容器中獲取,
獲取的key為DEFAULT_KEY +ViewModel.class.getCanonicalName()纵顾。沒有獲取到時通過Factory創(chuàng)建對應(yīng)ViewModel,并添加到Acactivitytivity中的ViewModelStore容器中伍茄,下次可以直接獲取到。
所以在一個Activity中同一個class對應(yīng)的ViewModel只會存在一個施逾,這也就是上面場景2的使用基礎(chǔ)敷矫。
3.2.清楚ViewModel的獲取流程后,接下來看ViewModel怎樣做到旋轉(zhuǎn)屏幕依然保持存活的汉额。
我們知道Activity在屏幕旋轉(zhuǎn)時默認(rèn)會重新創(chuàng)建Activity,新的Activity是不會保存原Activity的數(shù)據(jù)的曹仗,那ViewModel是怎樣跨Activity對象得到保存的呢?
根據(jù)3.1我們知道ViewModel存放在Activity的ViewModelStore中蠕搜,我們看一下activity.getViewModelStore():
--ComponentActivity.java
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) {
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
第一次獲取ViewModelStore時怎茫,會先調(diào)用getLastNonConfigurationInstance()獲取到一個NonConfigurationInstances對象,并嘗試從NonConfigurationInstances中獲取ViewModelStore,沒有獲取到時才會創(chuàng)建一個ViewModelStore轨蛤;
--ComponentActivity.java
NonConfigurationInstances mLastNonConfigurationInstances;
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
......
mLastNonConfigurationInstances = lastNonConfigurationInstances;
......
}
mLastNonConfigurationInstances是ComponentActivity中的一個變量蜜宪,它在Activity創(chuàng)建時attach()中被系統(tǒng)傳入。
mLastNonConfigurationInstances.activity的保存發(fā)生在
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
最后還有一個小細(xì)節(jié)祥山,在androidx.activity.ComponentActivity的構(gòu)造方法中對當(dāng)前Activity的生命周期進(jìn)行了監(jiān)聽圃验。
androidx.activity.ComponentActivity.java
public ComponentActivity() {
......
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
}
可以看到Activity在Destroy時,如果不是屏幕旋轉(zhuǎn)才會清空tViewModelStore()中的ViewModel缝呕。