Jetpack简介
在2018年Google I/O大会发布了一系列辅助android开发者的实用工具,统称Jetpack,Jetpack 是一套库、工具和指南,可帮助开发者更轻松地编写优质应用。这些组件可帮助您遵循最佳做法、让您摆脱编写样板代码的工作并简化复杂任务,以便您将精力集中放在所需的代码上。
ViewModel
这篇文章主要讲ViewModel的使用及原理。ViewModel主要用来管理UI与数据的交互,当屏幕的旋转、权限开启与关闭、内存不足回收Activity等会重新创建页面,页面数据就会丢失,而通过ViewModel来保存数据不会因为Activity的配置改变而发生变化。
基本使用
添加依赖:
allprojects {
repositories {
google()
jcenter()
}
}
dependencies {
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
implementation"androidx.lifecycle:lifecycle-viewmodel:2.0.0"
}
我们要使用ViewModel通常的做法是继承ViewModel,例如:
class MainViewModel : ViewModel() {
val noticeCount = MutableLiveData<Int>()
}
通常ViewModel和LiveData
配合使用,LiveData
后面再讲,其实LiveData
和RxJava
类似,都是基于观察者模式。创建好了ViewModel,接下来就是使用它,比如我们在Activity中使用:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val model = ViewModelProviders.of(this).get(MainViewModel::class.java)
model.noticeCount.observe(this, Observer{
//数据发生变化,更新UI
})
}
}
首先我们看ViewModelProviders.of(this)
这个静态方法,它有4个重载方法:
public static ViewModelProvider of(@NonNull Fragment fragment) {
return of(fragment, null);
}
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
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(fragment.getViewModelStore(), factory);
}
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);
}
of方法里首先先判断是否有factory
,没有则创建,默认使用AndroidViewModelFactory
。调用of方法获取到ViewModelProvider
对象,再调用get方法,get方法主要是通过AndroidViewModelFactory
中create
方法通过反射创建ViewModel实例。
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//在缓存中获取(内部通过HashMap缓存)
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//如果找到直接返回
return (T) viewModel;
} else {
if (viewModel != null) {
// TODO: log a warning.
}
}
//没有找到则通过Factory创建
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
...
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
...
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
//反射创建ViewModel
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} ...
return super.create(modelClass);
}
}
上面主要讲ViewModel是怎样获取的,接下来看一下ViewModel为什么不会随着Activity重建而造成数据丢失。在ViewModelProviders.of(this)
方法中获取Activity或Fragment中的ViewModelStore缓存作为参数创建了ViewModelProvider对象,那么ViewModelStore的缓存一定在Activity或Fragment中。当配置改变时,在onSaveInstanceState里保存数据,然后在onRestoreInstanceState恢复数据,但是onSaveInstanceState只能存放少量数据,viewModelStore存放的数据可能很大因此在onSaveInstanceState中存放viewModelStore并不合适,那么viewModelStore怎么保存的呢,通过查看源码原来是利用Activity中的onRetainNonConfigurationInstance和getLastNonConfigurationInstance方法。我们看一下ComponentActivity
中的getViewModelStore方法:
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,如果不为空再获取viewModelStore,当配置发生改变可以重写onRetainCustomNonConfigurationInstance方法传入自定义数据,当需要时再通过getLastNonConfigurationInstance获取
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
//如果没有获取到,创建ViewModelStore对象
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
ComponentActivity中onRetainNonConfigurationInstance保存viewModelStore
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// 如果NonConfigurationInstance保存了viewModelStore,把它取出来
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
//把viewModelStore放到NonConfigurationInstances中并返回
nci.viewModelStore = viewModelStore;
return nci;
}
onRetainNonConfigurationInstance的原理是什么呢,他的数据最终是怎样保存的呢,了解过Activity启动流程的都知道ActivityThread
,他就是我们所说的主线程,它控制着Activity的生命周期,当ActivityThread
执行performDestroyActivity
这个方法时,会调用Activity.retainNonConfigurationInstances获取到保存的数据并保存到ActivityClientRecord中。
ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance, String reason) {
...
if (getNonConfigInstance) {
try {
//保存retainNonConfigurationInstances中的数据到ActivityClientRecord中
r.lastNonConfigurationInstances
= r.activity.retainNonConfigurationInstances();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to retain activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
}
...
return r;
}
当页面重建数据保存下来了,那么数据是怎么恢复的呢,其实在ActivityThread创建Activity执行activity.attach时,会把lastNonConfigurationInstances
传递过来,这样就可以在lastNonConfigurationInstances中获取保存的viewModelStore了。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
}
当关闭Activity时,会清除viewModelStore。
getLifecycle().addObserver(new GenericLifecycleObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
这里使用的是Lifecycle监听生命周期,Lifecycle是什么先不管,它可以监听到Activity生命周期的变化,当Activity关闭调用onDestory时清空viewModelStore中的数据。