往年面试中有关Jetpack的考察能够算是加分项,随着官方对Modern Android development (MAD) 的大力推广,今年基本上都是必选题了。java
不少候选人对Jetpack各组件的功能及用法如数家珍,但一问及到原理每每卡壳。原理不清虽不影响API的使用,但也正由于如此,若是能对源码有必定了解,也许能够脱颖而出获得加分。android
本文分享一个入门级的源码分析,也是在面试中常常被问到的问题面试
ViewModel是Android Jetpack中的重要组件,其优点是具备下图这样的生命周期、不会由于屏幕旋转等Activity配置变化而销毁,是实现MVVM架构中UI状态管理的重要基础。 markdown
class MyActivity : AppCompatActivity {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate")
val activity: FragmentActivity = this
val factory: ViewModelProvider.Factory = ViewModelProvider.NewInstanceFactory()
// Activity因为横竖品切换销毁重建,此处的viewModel 仍然是重建前的实例
val viewModel = ViewModelProvider(activity, factory).get(MyViewModel::class.java)
// 若是直接new实例则会建立新的ViewModel实例
// val viewModel = MyViewModel()
Log.d(TAG, " - Activity :${this.hashCode()}")
Log.d(TAG, " - ViewModel:${viewModel.hashCode()}")
}
}
复制代码
上面代码在横竖屏切换时的log以下:架构
#Activity初次启动
onCreate
- Activity :132818886
- ViewModel:249530701
onStart
onResume
#屏幕旋转
onPause
onStop
onRetainNonConfigurationInstance
onDestroy
onCreate
- Activity :103312713 #Activity实例不一样
- ViewModel:249530701 #ViewModel实例相同
onStart
onResume
复制代码
下面代码是保证屏幕切换时ViewModel不销毁的关键,咱们依次为入口看一下源码app
val viewModel = ViewModelProvider(activity, factory).get(MyViewModel::class.java)
复制代码
ViewModelProvider源码很简单,分别持有一个ViewModelProvider.Factory
和ViewModelStore
实例ide
package androidx.lifecycle;
public class ViewModelProvider {
public interface Factory {
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
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;
}
...
}
复制代码
get()
返回ViewModel实例源码分析
package androidx.lifecycle;
public class ViewModelProvider {
...
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
...
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;
}
...
}
复制代码
逻辑很是清晰:this
package androidx.lifecycle;
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);
}
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
复制代码
可见,ViewModelStore就是一个对Map
的封装。spa
val viewModel = ViewModelProvider(activity, factory).get(FooViewModel::class.java)
复制代码
上面代码ViewModelProvider()构造参数1中传入的FragmentActivity
(基类是ComponentActivity
)其实是ViewModelStoreOwner
的一个实现。
package androidx.lifecycle;
public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore();
}
复制代码
ViewModelProvider中的ViewModelStore正是来自ViewModelStoreOwner。
public class ViewModelProvider {
private final ViewModelStore mViewModelStore;
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
this.mViewModelStore = store;
}
复制代码
Activity在onDestroy会尝试对ViewModelStore清空。若是是因为ConfigurationChanged带来的Destroy则不进行清空,避免横竖屏切换等形成ViewModel销毁。
//ComponentActivity.java
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// Clear out the available context
mContextAwareHelper.clearAvailableContext();
// And clear the ViewModelStore
if (!getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// Clear out the available context
mContextAwareHelper.clearAvailableContext();
// And clear the ViewModelStore
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});()) {
getViewModelStore().clear();
}
}
}
});
复制代码
FragmentActivity
实现了ViewModelStoreOwner
的getViewModelStore
方法
package androidx.fragment.app;
public class FragmentActivity extends ComponentActivity implements ViewModelStoreOwner ... {
private ViewModelStore mViewModelStore;
@NonNull
@Override
public ViewModelStore getViewModelStore() {
...
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
FragmentManagerNonConfig fragments;
}
...
}
复制代码
经过getLastNonConfigurationInstance()
获取 NonConfigurationInstances
实例,从而获得真正的viewModelStore
,getLastNonConfigurationInstance()
又是什么?
package android.app;
public class Activity extends ContextThemeWrapper implements ... {
/* package */ NonConfigurationInstances mLastNonConfigurationInstances;
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
复制代码
Retrieve the non-configuration instance data that was previously returned by onRetainNonConfigurationInstance(). This will be available from the initial onCreate(Bundle) and onStart() calls to the new instance, allowing you to extract any useful dynamic state from the previous instance.
经过官方文档咱们知道,屏幕旋转前经过onRetainNonConfigurationInstance()
返回的Activity实例,屏幕旋转后能够经过getLastNonConfigurationInstance()
获取,所以屏幕旋转先后不销毁的关键就在onRetainNonConfigurationInstance
#Activity初次启动
onCreate
- Activity :132818886
- ViewModel:249530701
onStart
onResume
#屏幕旋转
onPause
onStop
onRetainNonConfigurationInstance
onDestroy
onCreate
- Activity :103312713 #Activity实例不一样
- ViewModel:249530701 #ViewModel实例相同
onStart
onResume
复制代码
屏幕旋转时,onRetainNonConfigurationInstance()
在onStop
和onDestroy
之间调用
package android.app;
public class Activity extends ContextThemeWrapper implements ... {
public Object onRetainNonConfigurationInstance() {
return null;
}
...
}
复制代码
onRetainNonConfigurationInstance
在Activity中只有空实现,在FragmentActivity
中被重写
package androidx.fragment.app;
public class FragmentActivity extends ComponentActivity implements ViewModelStoreOwner, ... {
@Override
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
if (fragments == null && mViewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = mViewModelStore;
nci.fragments = fragments;
return nci;
}
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
FragmentManagerNonConfig fragments;
}
...
}
复制代码
FragmentActivity 经过 onRetainNonConfigurationInstance() 返回 了存放ViewModelStore的NonConfigurationInstances 实例。 值得一提的是onRetainNonConfigurationInstance
提供了一个hook时机:onRetainCustomNonConfigurationInstance
,容许咱们像ViewModel同样使得自定义对象不被销毁
NonConfigurationInstances会在attach
中由系统传递给新重建的Activity:
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) 复制代码
而后在onCreate
中,经过getLastNonConfigurationInstance()
获取NonConfigurationInstances中的ViewModelStore
package androidx.fragment.app;
public class FragmentActivity extends ComponentActivity implements ViewModelStoreOwner ... {
private ViewModelStore mViewModelStore;
@SuppressWarnings("deprecation")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null && nc.viewModelStore != null && mViewModelStore == null) {
mViewModelStore = nc.viewModelStore;
}
...
}
}
复制代码