一箕昭、ViewModel的簡(jiǎn)介
2018年谷歌IO大會(huì)上正式發(fā)布了JetPack組件灵妨,其中包括Databing、Lifecycles落竹、LiveData泌霍、Navigation、Paging述召、Room朱转、ViewModel、WorkManager等一系列框架积暖。并且發(fā)布androidx包藤为,這些框架的最新版本組件將引入到androidx包下。
JetPack架構(gòu)組件的發(fā)布呀酸,意味著google終于拿出了官方推薦的Android開發(fā)架構(gòu)凉蜂,一直以來在Android開發(fā)上老生常談三種開發(fā)模式琼梆,MVC性誉、MVP、MVVM茎杂。整體的思想就是做一些代碼封裝和操作上的分離错览,具體三種架構(gòu)的區(qū)別不在這詳細(xì)描述。說一點(diǎn)兒個(gè)人對(duì)這三中開發(fā)模式的理解煌往。
MVC:Activity承擔(dān)C的任務(wù)倾哺,強(qiáng)行carry大量業(yè)務(wù)和數(shù)據(jù)代碼。
MVP:Presenter承擔(dān)主要代碼任務(wù)刽脖,連接數(shù)據(jù)層和視圖層的交互羞海。
MVVM:Model負(fù)責(zé)數(shù)據(jù)、View負(fù)責(zé)展示曲管、ViewModel負(fù)責(zé)Model和View的交互却邓,同時(shí),最好的一點(diǎn)是View層自動(dòng)監(jiān)聽ViewModel的數(shù)據(jù)變化院水。
在JetPack組件出現(xiàn)之前腊徙,一直以來構(gòu)建MVVM架構(gòu)的方式都是代用Databing來充當(dāng)ViewModel简十,而Databing是采用標(biāo)簽方式寫入布局文件中的,這樣一來當(dāng)出現(xiàn)問題的時(shí)候不是太好進(jìn)行調(diào)試撬腾。所以ViewMode的出現(xiàn)對(duì)于MVVM模式開發(fā)具有重大的意義螟蝙。
二、ViewModel的用法和特點(diǎn)
ViewModel的使用是要結(jié)合LiveData框架進(jìn)行的民傻,LiveData框架也是JetPack組件的一部分胰默,這里先不詳細(xì)進(jìn)行介紹。ViewModel有兩個(gè)特點(diǎn)漓踢,一是更加方便的保存數(shù)據(jù)初坠,第二個(gè)特點(diǎn),也是最重要的特點(diǎn)彭雾,就是保證數(shù)據(jù)不受Activity的銷毀重建所影響碟刺,當(dāng)Activity銷毀重建后仍然能收到之前的數(shù)據(jù)。
1)繼承ViewModel
class MainViewModel : ViewModel() {
private val repertory: MainRepository by lazy { MainRepository() }
var data: MutableLiveData<JsonBean> = MutableLiveData()
fun getDataFromServer(){
repertory.getDataFromServer(data)
}
}
ViewModel中持有LiveData薯酝,LiveData是ViewModel持有數(shù)據(jù)的載體半沽。
2)Activity通過ViewModelProviders獲取ViewModel
class MainActivity : AppCompatActivity() {
private lateinit var mModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initData()
}
private fun initData() {
mModel = ViewModelProviders.of(this)[MainViewModel::class.java]
mModel.data?.observe(this, Observer {
val mainAdapter = MainAdapter(this, it)
val linearLayoutManager = LinearLayoutManager(this)
rv.layoutManager = linearLayoutManager
rv.adapter = mainAdapter
})
mModel.getDataFromServer()
}
}
3)通過ViewModel中的方法獲取數(shù)據(jù)然后改變LiveData狀態(tài),通過響應(yīng)式的方式通知到Activity進(jìn)行視圖更新吴菠。用法上比較簡(jiǎn)單者填。
三、源碼分析
個(gè)人認(rèn)為對(duì)于一個(gè)框架的學(xué)習(xí)僅僅掌握框架的用法是不夠的做葵,因?yàn)檫@太簡(jiǎn)單了占哟,曾經(jīng)看到過一篇博客,里面有一句話說的很好酿矢,”如果你只會(huì)用這個(gè)框架榨乎,而不清楚其中的原理和設(shè)計(jì),那么即便這個(gè)框架性能再好瘫筐,再牛逼蜜暑,那也是寫框架的那個(gè)人牛逼,而不是你牛逼“策肝。我認(rèn)為這句話說的很好肛捍,所以當(dāng)我們學(xué)習(xí)一中新框架的時(shí)候,不能單單只會(huì)用之众,一定要清楚其中的原理拙毫,盡量去理解作者的設(shè)計(jì)思想,就像品茶一樣棺禾,這樣才能品出里面的滋味缀蹄。不扯閑篇了,由于作者能力也有限,所以以上和以下分析袍患,如有不同觀點(diǎn)或作者描述有誤請(qǐng)給予批評(píng)指正坦康,歡迎來噴。
1)先從獲取ViewModel的類入手诡延,”ViewModelProviders“從類名中也能分析出這個(gè)類是用于提供ViewModel的滞欠。源碼如下:
public class ViewModelProviders {
public ViewModelProviders() {
}
private static Application checkApplication(Activity activity) {
Application application = activity.getApplication();
if (application == null) {
throw new IllegalStateException("Your activity/fragment is not yet attached to "
+ "Application. You can't request ViewModel before onCreate call.");
}
return application;
}
private static Activity checkActivity(Fragment fragment) {
Activity activity = fragment.getActivity();
if (activity == null) {
throw new IllegalStateException("Can't create ViewModelProvider for detached fragment");
}
return activity;
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment) {
ViewModelProvider.AndroidViewModelFactory factory =
ViewModelProvider.AndroidViewModelFactory.getInstance(
checkApplication(checkActivity(fragment)));
return new ViewModelProvider(ViewModelStores.of(fragment), factory);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
ViewModelProvider.AndroidViewModelFactory factory =
ViewModelProvider.AndroidViewModelFactory.getInstance(
checkApplication(activity));
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment, @NonNull Factory factory) {
checkApplication(checkActivity(fragment));
return new ViewModelProvider(ViewModelStores.of(fragment), factory);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@NonNull Factory factory) {
checkApplication(activity);
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}
@SuppressWarnings("WeakerAccess")
@Deprecated
public static class DefaultFactory extends ViewModelProvider.AndroidViewModelFactory {
/**
* Creates a {@code AndroidViewModelFactory}
*
* @param application an application to pass in {@link AndroidViewModel}
* @deprecated Use {@link ViewModelProvider.AndroidViewModelFactory} or
* {@link ViewModelProvider.AndroidViewModelFactory#getInstance(Application)}.
*/
@Deprecated
public DefaultFactory(@NonNull Application application) {
super(application);
}
}
}
我們從中可以看到,這個(gè)類中的方法全是靜態(tài)的肆良,說明這個(gè)類相當(dāng)于一個(gè)工具類筛璧,從of方法中我們可以看到真正實(shí)現(xiàn)ViewModel創(chuàng)建的類是ViewModelProvider,而這個(gè)類的構(gòu)建又需要通過ViewModelStores的of方法獲取惹恃,ViewModelStores的代碼如下:
public class ViewModelStores {
private ViewModelStores() {
}
@NonNull
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}
@NonNull
@MainThread
public static ViewModelStore of(@NonNull Fragment fragment) {
if (fragment instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) fragment).getViewModelStore();
}
return holderFragmentFor(fragment).getViewModelStore();
}
}
從這個(gè)類中可以發(fā)現(xiàn)獲取ViewModelStore是通過構(gòu)建一個(gè)HoldFragment夭谤,而這個(gè)HoldFragment的作用就是持有ViewModelStore的引用,然后將這個(gè)Fragment添加到Activity中巫糙,而且這個(gè)Fragmet有一個(gè)重要的特點(diǎn)朗儒,在實(shí)例化的時(shí)候會(huì)調(diào)用setRetainInstance(true)方法,這個(gè)方法的作用是讓Fragment不受Activity銷毀重建影響参淹,這樣一來就能保證ViewModel不會(huì)由于Activity的銷毀重建導(dǎo)致數(shù)據(jù)丟失醉锄,這是ViewModel的一個(gè)重要特性。這種設(shè)計(jì)確實(shí)很巧妙浙值,HolderFragment的代碼如下:
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class HolderFragment extends Fragment implements ViewModelStoreOwner {
.......省略部分代碼
public HolderFragment() {
setRetainInstance(true);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sHolderFragmentManager.holderFragmentCreated(this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public void onDestroy() {
super.onDestroy();
mViewModelStore.clear();
}
@NonNull
@Override
public ViewModelStore getViewModelStore() {
return mViewModelStore;
}
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(Fragment fragment) {
return sHolderFragmentManager.holderFragmentFor(fragment);
}
.....省略部分代碼
private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
HolderFragment holder = new HolderFragment();
fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
return holder;
}
HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
HolderFragment holder = findHolderFragment(fm);
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);
mNotCommittedActivityHolders.put(activity, holder);
return holder;
}
HolderFragment holderFragmentFor(Fragment parentFragment) {
FragmentManager fm = parentFragment.getChildFragmentManager();
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
holder = mNotCommittedFragmentHolders.get(parentFragment);
if (holder != null) {
return holder;
}
parentFragment.getFragmentManager()
.registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false);
holder = createHolderFragment(fm);
mNotCommittedFragmentHolders.put(parentFragment, holder);
return holder;
}
}
之后來到ViewModelProvider恳不,代碼量不是很多,但是里面的設(shè)計(jì)確實(shí)很有意思开呐。首先來分析它的成員變量烟勋,成員變量只有兩個(gè),F(xiàn)actory從字面的意思就能理解筐付,它是生產(chǎn)ViewModel的工廠卵惦,所以這里用到了工廠模式。ViewModelStore它用來存儲(chǔ)ViewModel家妆,相當(dāng)于ViewModel的緩存鸵荠。內(nèi)部是一個(gè)HashMap,key是ViewModel的類名稱伤极。ViewModelProvider代碼如下:
public class ViewModelProvider {
....省略部分代碼
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
......
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
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();
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)) {
//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;
.......省略部分代碼
}
2)Factory是ViewModelProvider中的一個(gè)接口,定義如下:
public interface Factory {
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
通過create方法創(chuàng)建ViewModel姨伤。Factory有兩個(gè)實(shí)現(xiàn)類AndroidViewModelFactory哨坪、NewInstanceFactory都是ViewModelProvider中的靜態(tài)內(nèi)部類。同時(shí)AndroidViewModelFactory又繼承于NewInstanceFactory乍楚。有一種依賴注入的思想在里面当编。接下來我們來分析兩個(gè)Factory的實(shí)現(xiàn)類。NewInstanceFactory最終通過newinstance方法創(chuàng)建ViewModel實(shí)例徒溪。
public static class NewInstanceFactory implements Factory {
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
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);
}
}
}
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);
}
}
最后忿偷,真正存儲(chǔ)ViewModel的容器是ViewModelStore金顿,ViewModelStore中維護(hù)了一個(gè)HashMap,代碼如下:
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);
}
/**
* 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();
}
}