提纲
- ViewModel是什么
- ViewModel的优势
- ViewModel基本用法
- ViewModel相关方法说明及实现原理
一、ViewModel是什么
ViewModel
具备宿主生命周期感知能力的数据存储组件,使用ViewModel
保存的数据,在页面因配置变更导致页面销毁重建之后依然也是存在的。
配置变更:横竖屏切换、分辨率调整、权限变更、系统字体样式变更等
二、ViewModel的优势
2.1 页面配置更改数据不丢失
当设备因配置更改导致 Activity/Fragment 重建,ViewModel 中的数据并不会因此而丢失;
配合 LiveData 可以在页面重建后立马能收到最新保存的数据用以重新渲染页面。
2.2 生命周期感应
当在 ViewModel 中做一些网络请求或数据的处理时,可以复写 onCleared() 方法,终止清理一些操作,释放内存。该方法在宿主 onDestroy 时被调用。
2.2 数据共享
- Activity + Fragment 的页面,可以使用 ViewModel 实现页面之间的数据共享;
- 不同的 Activity也可以实现数据共享。
三、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相关方法说明及实现原理
4.1 相关方法说明
4.1.1 ViewModelProvider(@NonNull ViewModelStoreOwner owner)
构造方法
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实例
@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) {
// 通过key在ViewModelStore中取Value(ViewModel)
// ViewModelStore是真正存储ViewModel的地方,其内部维护了一个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.
}
}
// 不存在 创建viewModel实例
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 实现原理
ViewModel
可以实现因配置变更导致页面销毁重建之后依然可以复用。准确点来说,应该是页面恢复重建前后获取到的是同一个 ViewModel 实例对象。
ViewModelProvider
本质是从传递进去的 ViewModelStore
来获取实例。如果没有传递,则利用 factory 去创建一个新的,并存储到 ViewModelStore
。
4.2.1 ViewModelStoreOwner在Activity中的实现
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;
/**
* 应为配置变更导致的act重建时回调的方法
* getLastNonConfigurationInstance() 方法,是在窗口重建后获取重建前保存的数据
*/
@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对象中保存
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,可能窗口已经被重建
if (mViewModelStore == null) {
// 获取重建前保存的NonConfigurationInstances对象,从而获取mViewModelStore,并赋值当前mViewModelStore
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
// 如果还为null,说明窗口是第一次被创建
if (mViewModelStore == null) {
// 直接new一个对象
mViewModelStore = new ViewModelStore();
}
}
// 返回ViewModelStore
return mViewModelStore;
}
}
4.2.2 ViewModelStoreOwner在Fragment中的实现
# 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;
}
}