提綱
- ViewModel是什么
- ViewModel的優(yōu)勢(shì)
- ViewModel基本用法
- ViewModel相關(guān)方法說(shuō)明及實(shí)現(xiàn)原理
一、ViewModel是什么
ViewModel 具備宿主生命周期感知能力的數(shù)據(jù)存儲(chǔ)組件,使用ViewModel保存的數(shù)據(jù),在頁(yè)面因配置變更導(dǎo)致頁(yè)面銷毀重建之后依然也是存在的。
配置變更:橫豎屏切換、分辨率調(diào)整、權(quán)限變更、系統(tǒng)字體樣式變更等
二、ViewModel的優(yōu)勢(shì)
2.1 頁(yè)面配置更改數(shù)據(jù)不丟失
當(dāng)設(shè)備因配置更改導(dǎo)致 Activity/Fragment 重建,ViewModel 中的數(shù)據(jù)并不會(huì)因此而丟失;
配合 LiveData 可以在頁(yè)面重建后立馬能收到最新保存的數(shù)據(jù)用以重新渲染頁(yè)面。
2.2 生命周期感應(yīng)
當(dāng)在 ViewModel 中做一些網(wǎng)絡(luò)請(qǐng)求或數(shù)據(jù)的處理時(shí),可以復(fù)寫 onCleared() 方法,終止清理一些操作,釋放內(nèi)存。該方法在宿主 onDestroy 時(shí)被調(diào)用。
2.2 數(shù)據(jù)共享
- Activity + Fragment 的頁(yè)面,可以使用 ViewModel 實(shí)現(xiàn)頁(yè)面之間的數(shù)據(jù)共享;
- 不同的 Activity也可以實(shí)現(xiàn)數(shù)據(jù)共享。
三、ViewModel基本用法
data class MyData(var name:String,var age:Int,var sex:Int)
class MyModel : ViewModel(){
private val liveData = MutableLiveData<List<MyData>>()
fun loadData(): LiveData<List<MyData>> {
if (liveData.value == null){
val list = fromRemote()
liveData.postValue(list)
}
return liveData
}
fun fromRemote() = listOf(MyData("1",1,1),MyData("2",2,2))
}
class MainActivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
val viewModel = ViewModelProvider(this).get(MyModel::class.java)
viewModel.loadData().observe(this, Observer {
// TODO: do something
})
}
}
四、ViewModel相關(guān)方法說(shuō)明及實(shí)現(xiàn)原理
4.1 相關(guān)方法說(shuō)明
4.1.1 ViewModelProvider(@NonNull ViewModelStoreOwner owner) 構(gòu)造方法
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
// 賦值mFactory和mViewModelStore
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
4.1.2 T get(@NonNull String key, @NonNull Class<T> modelClass) 獲取ViewModel實(shí)例
@NonNull
@MainThread
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);
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
// 通過(guò)key在ViewModelStore中取Value(ViewModel)
// ViewModelStore是真正存儲(chǔ)ViewModel的地方,其內(nèi)部維護(hù)了一個(gè)HashMap<String,ViewModel>
ViewModel viewModel = mViewModelStore.get(key);
// viewModel是否存在
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
// 存在 返回
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
// 不存在 創(chuàng)建viewModel實(shí)例
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
// 添加到Map中
mViewModelStore.put(key, viewModel);
// 返回
return (T) viewModel;
}
4.2 實(shí)現(xiàn)原理
ViewModel 可以實(shí)現(xiàn)因配置變更導(dǎo)致頁(yè)面銷毀重建之后依然可以復(fù)用。準(zhǔn)確點(diǎn)來(lái)說(shuō),應(yīng)該是頁(yè)面恢復(fù)重建前后獲取到的是同一個(gè) ViewModel 實(shí)例對(duì)象。
ViewModelProvider本質(zhì)是從傳遞進(jìn)去的 ViewModelStore來(lái)獲取實(shí)例。如果沒(méi)有傳遞,則利用 factory 去創(chuàng)建一個(gè)新的,并存儲(chǔ)到 ViewModelStore。
4.2.1 ViewModelStoreOwner在Activity中的實(shí)現(xiàn)
public class ComponentActivity extends androidx.core.app.ComponentActivity implements ViewModelStoreOwner,... {
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
// Lazily recreated from NonConfigurationInstances by getViewModelStore()
private ViewModelStore mViewModelStore;
/**
* 應(yīng)為配置變更導(dǎo)致的act重建時(shí)回調(diào)的方法
* getLastNonConfigurationInstance() 方法,是在窗口重建后獲取重建前保存的數(shù)據(jù)
*/
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
// 將viewModelStore包裝成NonConfigurationInstances對(duì)象中保存
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
@NonNull
@Override
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.");
}
// mViewModelStore為null,可能窗口已經(jīng)被重建
if (mViewModelStore == null) {
// 獲取重建前保存的NonConfigurationInstances對(duì)象,從而獲取mViewModelStore,并賦值當(dāng)前mViewModelStore
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
// 如果還為null,說(shuō)明窗口是第一次被創(chuàng)建
if (mViewModelStore == null) {
// 直接new一個(gè)對(duì)象
mViewModelStore = new ViewModelStore();
}
}
// 返回ViewModelStore
return mViewModelStore;
}
}
4.2.2 ViewModelStoreOwner在Fragment中的實(shí)現(xiàn)
# Fragment
public class Fragment implements ViewModelStoreOwner {
// Internal unique name for this fragment;
@NonNull
String mWho = UUID.randomUUID().toString();
// The fragment manager we are associated with. Set as soon as the
// fragment is used in a transaction; cleared after it has been removed
// from all transactions.
FragmentManagerImpl mFragmentManager;
// Host this fragment is attached to.
FragmentHostCallback mHost;
@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
return mFragmentManager.getViewModelStore(this);
}
}
# FragmentManagerImpl
/**
* Container for fragments associated with an activity.
*/
final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
FragmentHostCallback mHost;
private FragmentManagerViewModel mNonConfig;
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
return mNonConfig.getViewModelStore(f);
}
@NonNull
FragmentManagerViewModel getChildNonConfig(@NonNull Fragment f) {
return mNonConfig.getChildNonConfig(f);
}
}
# FragmentManagerViewModel
/**
* FragmentManagerViewModel is the always up to date view of the Fragment's
* non configuration state
*/
class FragmentManagerViewModel extends ViewModel {
private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() {
@NonNull
@Override
@SuppressWarnings("unchecked")
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
FragmentManagerViewModel viewModel = new FragmentManagerViewModel(true);
return (T) viewModel;
}
};
@NonNull
static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
ViewModelProvider viewModelProvider = new ViewModelProvider(viewModelStore,
FACTORY);
return viewModelProvider.get(FragmentManagerViewModel.class);
}
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
if (viewModelStore == null) {
viewModelStore = new ViewModelStore();
mViewModelStores.put(f.mWho, viewModelStore);
}
return viewModelStore;
}
}