- 继承ViewModel,初始化 User
- 声明私有的 user LIveData 用来更新数据
- 对外暴露的,不可更改 value 值的LiveData
- updateUser() 更新 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的关键代码
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
最后
如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。
最后针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
需要资料的朋友可以点击我的GitHub免费领取
1321722473)]
最后
如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。
[外链图片转存中…(img-XJotX4UQ-1711321722474)]
最后针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!