打印UserViewModel对象的地址值,来看日志

3.3.结果日志

E/FirstFragment: userViewModel = com.jhb.awesomejetpack.viewmodel.UserViewModel@9940311 E/SecondFragment: userViewModel = com.jhb.awesomejetpack.viewmodel.UserViewModel@9940311

可以看到两个 Fragment 中 UserViewModel是同一个对象。

可以这两个 Fragment 可以使用其 Activity 范围共享 ViewModel 来处理此类通信

4.抛出问题

ViewModel为什么不会随着Activity的屏幕旋转而销毁;为什么在对应的作用域内,保正只生产出对应的唯一实例,保证UI组件间的通信onCleared方法在什么调用

5.分析源码前的准备工作

5.1ViewModel 的生命周期

5.2.几个类的感性认识

ViewModelStoreOwner:是一个接口,用来获取一个ViewModelStore对象 ViewModelStore:存储多个ViewModel,一个ViewModelStore的拥有者( Activity )在配置改变, 重建的时候,依然会有这个实例 ViewModel:一个对 Activity、Fragment 的数据管理类,通常配合 LiveData 使用 ViewModelProvider:创建一个 ViewModel 的实例,并且在给定的ViewModelStoreOwner中存储 ViewModel

6.源码分析

再看上面第一个例子中的代码

class ViewModelActivity : AppCompatActivity() {

//初始化 UserViewModel 通过 ViewModelProvider private val userViewModel by lazy { ViewModelProvider(this)[UserViewModel::class.java] }

override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val button = Button(this) setContentView(button)

//观察 User 数据,并打印 userViewModel.userLiveData.observe(this, Observer { user -> “User = $user”.log() })

//点击按钮更新 User 信息 button.setOnClickListener { userViewModel.updateUser() } } }

首先看下UserViewModel的初始化过程。

private val userViewModel by lazy { ViewModelProvider(this)[UserViewModel::class.java] }

注:上面代码类似数组的写法是 Kotlin 的写法,其实是 ViewModelProvider 的get方法

7.ViewModelProvider的构造方法,以及 get 方法

7.1ViewModelProvider构造方法

先看ViewModelProvider构造方法,传入的参数为当前的 AppCompatActivity

//ViewModelProvider.java

private final Factory mFactory; private final ViewModelStore mViewModelStore;

public ViewModelProvider(@NonNull ViewModelStoreOwner owner) { this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory() : NewInstanceFactory.getInstance()); }

public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) { mFactory = factory; mViewModelStore = store; }

通过 ViewModelStoreOwner获取ViewModelStore对象并给 mViewModelStore赋值给mFactory赋值,这里赋值的是NewInstanceFactory这个对象

7.2.ViewModelProvider的 get 方法

//ViewModelProvider.java

private static final String DEFAULT_KEY = “androidx.lifecycle.ViewModelProvider.DefaultKey”;

public T get(@NonNull Class modelClass) { String canonicalName = modelClass.getCanonicalName(); if (canonicalName == null) { throw new IllegalArgumentException(“Local and anonymous classes can not be ViewModels”); } //1 return get(DEFAULT_KEY + “:” + canonicalName, modelClass); }

注释1:

调用了两个参数的 get 方法 第一个参数是字符串的拼接,用来以后获取对应 ViewModel 实例的,保证了同一个 Key 取出是同一个 ViewModel 第二参数是 UserViewModel 的字节码文件对象

看下两个参数的get方法

//ViewModelProvider.java public T get(@NonNull String key, @NonNull Class modelClass) { ViewModel viewModel = mViewModelStore.get(key);//1 //2 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. } } //3 if (mFactory instanceof KeyedFactory) { viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass); } else { viewModel = (mFactory).create(modelClass); } //4 mViewModelStore.put(key, viewModel); return (T) viewModel; }

注释 1:从ViewModelStore中,根据 key,取一个 ViewModel,ViewModelStore源码下文分析

注释 2:判断取出来的 ViewModel 实例和传进来的是否是一个,是同一个,直接返回此缓存中实例

注释 3:通过Factory创建一个ViewModel

注释 4:把新创建的ViewModel用ViewModelStore存储起来,以备下次使用,最后返回新创建的ViewModelStore

这里看一下ViewModel是怎么通过Factory创建出来的

通过 7.1 小节可以知道,这个Factory的实例是NewInstanceFactory

7.3.NewInstanceFactory的create方法

//ViewModelProvider.java 中的 AndroidViewModelFactory.java public T create(@NonNull Class 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); } }

简单粗暴,通过反射,直接创建了ViewModel对象。

这里扩展一个,在实例UserViewModel的时候

private val userViewModel by lazy { ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(application))[UserViewModel::class.java] }

也可以通过两个参数的构造方法,来实例化,其中第二个参数就是Factory类型。然后就会用 AndroidViewModelFactory来实例化UserViewModel,我们来具体看下代码

AndroidViewModelFactory是NewInstanceFactory的子类

//ViewModelProvider.java 中的 AndroidViewModelFactory public T create(@NonNull Class 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); }

如果我们创建的UserViewModel当初继承的是AndroidViewModel类就走modelClass.getConstructor(Application.class).newInstance(mApplication);实例化方法,否则就走父类的实例化方法,也就是NewInstanceFactory的create方法

在开发中建议使用AndroidViewModel类,它会提供给一个Application级别的 Context。

接下来看一下ViewModelStoreOwner是什么,以及它的具体实现

8.ViewModelStoreOwner

public interface ViewModelStoreOwner { /**

Returns owned {@link ViewModelStore} @return a {@code ViewModelStore} */ @NonNull ViewModelStore getViewModelStore(); } 一个接口,里面一个方法返回了ViewModelStore对象 它的实现类在 AndroidX 中ComponentActivity和 Fragment

ComponentActivity的关键代码

//ComponentActivity.java public class ComponentActivity extends androidx.core.app.ComponentActivity implements ViewModelStoreOwner,XXX{

private ViewModelStore mViewModelStore;

@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.”); } 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; } }

创建了一个ViewModelStore并返回了

来看下这个ViewModelStore类

9.ViewModelStore

9.1.ViewModelStore的源码

我下面贴的是完整代码,对你没看错。

public class ViewModelStore { //1 private final HashMap mMap = new HashMap<>(); //2 final void put(String key, ViewModel viewModel) { ViewModel oldViewModel = mMap.put(key, viewModel); if (oldViewModel != null) { oldViewModel.onCleared(); } } //3 final ViewModel get(String key) { return mMap.get(key); }

Set keys() { return new HashSet<>(mMap.keySet()); }

//4 public final void clear() { for (ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); } }

注释 1 :声明一个 Map 来存储ViewModel

注释 2:存储ViewModel,这个方法我们在7.2 小节ViewModelProvider的 get 方法中用到过

注释 3:取出 ViewModel,这个方法我们在7.2 小节ViewModelProvider的 get 方法中用到过。注意在从 Map中去 ViewModel 的时候是根据 Key,也就是7.2小节注释 1 拼接的那个字符串DEFAULT_KEY + “:” + canonicalName。这也就解释了第 4 节的疑问 为什么在对应的作用域内,保正只生产出对应的唯一实例

注释 4:这个是一个重点方法了,表明要清空存储的数据,还会调用到ViewModel的 clear 方法,也就是最终会调用带 ViewModel 的onCleared()方法

那么这个ViewModelStore的 clear 方法,什么时候会调用呢?

9.2.ComponentActivity的构造方法

//ComponentActivity.java public ComponentActivity() { Lifecycle lifecycle = getLifecycle();

getLifecycle().addObserver(new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { //1 if (event == Lifecycle.Event.ON_DESTROY) { if (!isChangingConfigurations()) { getViewModelStore().clear(); } } } });

}

在ComponentActivity的构造方法中,我们看到,在 Activity 的生命周期为 onDestory的时候,并且当前不是,配置更改(比如横竖屏幕切换)就会调用ViewModelStore 的 clear 方法,进一步回调用 ViewModel 的onCleared方法。

这就回答了第四节提出的问题onCleared方法在什么调用

最后看一下 ViewModel 的源码,以及其子类AndroidViewModel

10.ViewModel 的源码

ViewModel类其实更像是更规范化的抽象接口

public abstract class ViewModel { private volatile boolean mCleared = false;

@SuppressWarnings(“WeakerAccess”) protected void onCleared() { }

@MainThread final void clear() { mCleared = true; if (mBagOfTags != null) { synchronized (mBagOfTags) { for (Object value : mBagOfTags.values()) { // see comment for the similar call in setTagIfAbsent closeWithRuntimeException(value); } } } onCleared(); }

}

ViewModel 的子类AndroidViewModel

public class AndroidViewModel extends ViewModel { @SuppressLint(“StaticFieldLeak”) private Application mApplication;

public AndroidViewModel(@NonNull Application application) { mApplication = application; }

/**

Return the application. */ @SuppressWarnings({“TypeParameterUnusedInFormals”, “unchecked”}) @NonNull public T getApplication() { return (T) mApplication; } }

提供了一个规范,提供了一个 Application 的 Context

到现在整个源码过程就看了,包括前面,我们提到的那几个关键类的源码。

到目前为止,我们第 4 节抛出的问题,已经解决了,两个了,还有一个ViewModel为什么不会随着Activity的屏幕旋转而销毁;

11.分析为啥ViewModel不会随着Activity的屏幕旋转而销毁

首先知道的是 ViewModel 不被销毁,是在一个 ViewModelStore 的 Map 中存着呢,所以要保证ViewModelStore不被销毁。

首先得具备一个前置的知识

在 Activity 中提供了 onRetainNonConfigurationInstance 方法,用于处理配置发生改变时数据的保存。随后在重新创建的 Activity 中调用 getLastNonConfigurationInstance 获取上次保存的数据。

11.1.onRetainNonConfigurationInstance方法

//ComponentActivity.java /**

Retain all appropriate non-config state. You can NOToverride this yourself! Use a {@link androidx.lifecycle.ViewModel} if you want toretain your own non config state. */ @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; } //1 NonConfigurationInstances nci = new NonConfigurationInstances(); nci.custom = custom; nci.viewModelStore = viewModelStore; 自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

【算法合集】

[外链图片转存中…(img-EA3bQYgt-1713209383756)]

【延伸Android必备知识点】

[外链图片转存中…(img-gmbTDkEL-1713209383757)]

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: