2.1首先看一下 UserViewModel这个文件

//UserViewModel.kt

//自定义 User 数据类 data class User(var userId: String = UUID.randomUUID().toString(), var userName: String)

class UserViewModel : ViewModel() {

private val userBean = User(userName = “刀锋之影”) // 私有的 user LiveData private val _user = MutableLiveData().apply { value = userBean } // 对外暴露的,不可更改 value 值的LiveData var userLiveData: LiveData = _user

//更新 User 信息 fun updateUser() { //重新给 _user 赋值 _user.value = userBean.apply { userId = UUID.randomUUID().toString() userName = “更新后: userName = 泰隆” } } }

自定义 User 数据类继承ViewModel,初始化 User声明私有的 user LIveData 用来更新数据对外暴露的,不可更改 value 值的LiveDataupdateUser() 更新 User 信息的方法

2.2.再看下ViewModelActivity的内容

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观察 User 数据,并打印结果点击按钮时,更新 User 信息

2.3.结果日志

//log 日志 User = User(userId=34c1a1a4-967e-439c-91e8-795b8c162997, userName=刀锋之影) User = User(userId=a6d0f09c-9c01-412a-ab4f-44bef700d298, userName=更新后: userName = 泰隆)

2.4总结:

以上就是 ViewModel 的简单使用,是配合 LiveData 的,具体 LiveData 的使用以及与原理分析,请看这篇文章

Android Jetpack组件LiveData基本使用和原理分析

通过上文可以 ViewModel 的定义以及特点,可以知道 ViewModel在对应的作用域内,保正只生产出对应的唯一实例,保证UI组件间的通信

我们来验证一下这个特点,我再写个例子,证明一下这个特点

3.验证ViewModel在对应的作用域内,保正只生产出对应的唯一实例

3.1.ViewModelActivity2类

在ViewModelActivity2中通过supportFragmentManager添加两个 Fragment

class ViewModelActivity2 : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_view_model) supportFragmentManager.beginTransaction() .add(R.id.flContainer, FirstFragment()) .add(R.id.flContainer, SecondFragment()) .commit() } }

3.2.两个 Fragment

class FirstFragment : Fragment() { private val TAG = javaClass.simpleName

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val userViewModel = ViewModelProvider(activity as ViewModelStoreOwner)[UserViewModel::class.java] “userViewModel = $userViewModel”.logWithTag(TAG) return super.onCreateView(inflater, container, savedInstanceState) } }

class SecondFragment : Fragment() { private val TAG = javaClass.simpleName

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val userViewModel = ViewModelProvider(activity as ViewModelStoreOwner)[UserViewModel::class.java] “userViewModel = $userViewModel”.logWithTag(TAG) return super.onCreateView(inflater, container, savedInstanceState) } }

在 FirstFragment和SecondFragment的onCreateView方法中实例化UserViewModel对象 其中的参数都为activity as ViewModelStoreOwner其实也就是ViewModelActivity2 打印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 方法中用到过

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

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

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

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

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

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

最后

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

同时我经过多年的收藏目前也算收集到了一套完整的学习资料以及高清详细的Android架构进阶学习导图及笔记分享给大家,希望对想成为架构师的朋友有一定的参考和帮助。

下面是部分资料截图,诚意满满:特别适合有开发经验的Android程序员们学习。

不论遇到什么困难,都不应该成为我们放弃的理由!

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

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

索成长,不成体系的学习效果低效漫长且无助。整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

同时我经过多年的收藏目前也算收集到了一套完整的学习资料以及高清详细的Android架构进阶学习导图及笔记分享给大家,希望对想成为架构师的朋友有一定的参考和帮助。

下面是部分资料截图,诚意满满:特别适合有开发经验的Android程序员们学习。

[外链图片转存中…(img-kTLuwDBb-1712539227634)]

不论遇到什么困难,都不应该成为我们放弃的理由!

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

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

好文推荐

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