Android Jetpack架构组件(三)—ViewModel
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack架构组件(三)—ViewModel相关的知识,希望对你有一定的参考价值。
参考技术A ViewModel:是以感知生命周期的形式来存储和管理视图相关的数据。ViewModel主要有以下的特点:
继承ViewMode,实现自定义ViewModel。
在Activity中使用LoginViewModel
首先查看ViewModel源码
可以看到,我们并没有手动调用 ViewModel 的构造函数来创建 ViewModel 实例,而是由 ViewModelProvider 来获取,其实ViewModel 初始化是在ViewModelProvider内部自己通过反射来构建出 ViewModel 实例。
ViewModelProvider 一共包含三个构造函数,可以看到,不管是哪种方式,最终都是要拿到两个构造参数:ViewModelStore 和 Factory,且都不能为 null。
Activity和Fragment实现了ViewModelStoreOwner和HasDefaultViewModelProviderFactory接口,这两个接口分别提供了ViewModelStore 和 Factory;
既然 Factory 实例也有了,下一步就是来调用 ViewModelProvider(this).get() 方法了。get() 方法需要我们传入 Class 对象,ViewModelProvider 需要拿到 Class 才能完成反射操作。在此方法里主要是通过 modelClass 来自动生成一个字符串 Key,并将参数转发给另外一个 get() 方法。
该方法会通过 key 从 ViewModelStore 里取 ViewModel 实例,如果取不到值或者是取出来的值类型不符,则会通过 mFactory.create(modelClass) 方法来反射初始化 ViewModel,并在返回初始化结果前将它存到 mViewModelStore 中,这样就完成了 ViewModel 的初始化流程了。
结论:ViewModel保持不变是因为ViewModelStore没有变化。
原因:Activity 每次获取 ViewModel 实例都会先尝试从 mViewModelStore 中取值,只有在取不到值的时候才会去重新构建一个新的 ViewModel 实例,且构建后的 ViewModel 实例也会被保存在mViewModelStore 中。那既然 Activity 可以在页面销毁重建的情况下获取到之前的 ViewModel 实例,那么不也就间接说明了在这种情况下 ViewModelStore 也是一直被保留着而没有被回收。
ComponentActivity 的 getViewModelStore() 方法获取 ViewModelStore 实例的来源有两种:
这里只要看第一种情况
NonConfigurationInstances 是 ComponentActivity 的一个静态内部类,其内部就包含了一个 ViewModelStore 成员变量,在 Activity 被重建时,其对应的 ViewModelStore 就被保存在了这。
通过查找引用,可以找到 ComponentActivity 就是在 onRetainNonConfigurationInstance() 方法里来完成 NonConfigurationInstances.viewModelStore 变量的赋值。从该方法名可以猜出,该方法就用于获取非配置项实例,以便在后续重建 Activity 时恢复数据。
通过查找方法引用,可以知道 onRetainNonConfigurationInstance() 又是被父类 android.app.Activity 的以下方法所调用,由父类去负责保留 NonConfigurationInstances 对象。
在 ActivityThread 类的以下方法存在调用,该方法用于回调 Activity 的 onDestroy 方法,在回调前会先将数据保存到 ActivityClientRecord 的 lastNonConfigurationInstances 字段中。
在重新启动 Activity 时,又会将数据 attach 到新的 Activity 实例上,将其作为 getLastNonConfigurationInstance() 方法的返回值。通过这种数据交接,重建前的 ViewModelStore 实例就会被重建后的 Activity 拿到,当中就保留了重建前 Activity 初始化的所有 ViewModel 实例,从而保障了 ViewModel 实例的不变性。
ViewModelProvider 提供的 Factory 接口实现类有两个:
如果想要通过其它类型的构造函数来初始化 ViewModel 的话,就需要我们自己来实现 ViewModelProvider.Factory 接口声明初始化逻辑了:
如果想使用同一个ViewModel类对应不同的实例对象,那么就需要在初始化的时候主动为它们指定不同的 Key,这样它们就可以一起被存到 ViewModelStore 的 HashMap 中了。
ViewModel回收是由于ViewModelStore清空 HashMap。
在 ComponentActivity 中通过监听Lifecycle状态,在Activity 在收到 ON_DESTROY 事件时,如果判断到是由于配置项更改导致了 Activity 被销毁,那么就不会调用 getViewModelStore().clear() 。如果是正常退出 Activity,那就会调用 getViewModelStore().clear() 方法,这样就会清空掉所有缓存的 ViewModel 实例了,ViewModel 的 clear() 方法也同时会被调用。
参考: 从源码看Jetpack
Android Jetpack架构组件——Lifecycle使用篇
概述
Lifecycle是一个持有组件生命周期状态的class,并且允许其他组件来观察生命周期的变化。并不局限于Activity或者Fragment。我们只知道生命周期是由操作系统或者进程中运行的代码进行管理。而且生命周期是Android工作原理的核心,所以应用必须遵循它们。否则会引起OOM或者Crash。
为什么需要使用Lifecycle管理生命周期
在此我们用官网提供的一个示例:
internal class MyLocationListener(
private val context: Context,
private val callback: (Location) -> Unit
)
fun start()
// connect to system location service
fun stop()
// disconnect from system location service
class MyActivity : AppCompatActivity()
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...)
myLocationListener = MyLocationListener(this) location ->
// update UI
public override fun onStart()
super.onStart()
myLocationListener.start()
// manage other components that need to respond
// to the activity lifecycle
public override fun onStop()
super.onStop()
myLocationListener.stop()
// manage other components that need to respond
// to the activity lifecycle
从逻辑上看这段代码其实没什么问题,但是在真实应用场景中,我们需要管理很多组件和当前页面的调用,以响应当前生命周期的状态。所以会导致我们在onStop和onStart中存放大量的代码,导致它们难以维护。
所以官方提供lifecycle就是为了可以帮助我们以弹性和隔离的方式解决这些问题。
如何使用Lifecycle
lifecycle依赖
如果需要使用lifecycle的依赖,需要家google的maven仓库添加到项目中,在项目中的build.gradle新增:
allprojects
repositories
google()
在你的工程目录中的build.gradle中新增如下依赖:
dependencies
def lifecycle_version = "2.2.0"
def arch_version = "2.1.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
// Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
// Annotation processor
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// optional - helpers for implementing LifecycleOwner in a Service
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
// optional - ReactiveStreams support for LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
// optional - Test helpers for LiveData
testImplementation "androidx.arch.core:core-testing:$arch_version"
使用方法
- 生命周期拥有者使用getLifecycle()或者实例,然后通过addObserver添加观察者。
- 观察者实现LifecycleObserver接口,通过使用OnLifecycleEvent注解关注相应的生命周期。
使用示例
我们这里依然使用官方的例子:
class MyObserver : LifecycleObserver
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun connectListener()
...
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun disconnectListener()
...
myLifecycleOwner.getLifecycle().addObserver(MyObserver())
首先MyObserver实现LifecycleObserver接口,并使用ON_RESUME和ON_PAUSE注解对方法加上了生命周期的限制。然后拥有者直接通过添加观察者的形式进行调用即可。
实现自定义的LifecycleOwner
在26.1.0及更高版本中的Fragment和Activity已经默认实现了LifecycleOwner接口。
如果你需要自定义类并希望它成为LifecycleOwner。你可以使用 LifecycleRegistry。示例代码如下:
class MyActivity : Activity(), LifecycleOwner
private lateinit var lifecycleRegistry: LifecycleRegistry
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
lifecycleRegistry = LifecycleRegistry(this)
lifecycleRegistry.markState(Lifecycle.State.CREATED)
public override fun onStart()
super.onStart()
lifecycleRegistry.markState(Lifecycle.State.STARTED)
override fun getLifecycle(): Lifecycle
return lifecycleRegistry
通过makeState设置Lifecycle的各种状态,然后通过getLifecycle返回该实例。
实战
我们简单通过lifecycle对应用的前后台进行一个监听。我们先看下我们使用lifecycle之前是怎么对应用的前后台监听的。
/**
* @date:2020/12/30
* @author:Silence
* @describe:
**/
open class BaseActivityLifecycleCallback : Application.ActivityLifecycleCallbacks
private var currentResumedActivity: WeakReference<Activity>? = null
//监听app前后台的监听器
private var listener: OnAppStatusListener? = null
//打开的Activity数量统计
private var activityStartCount = 0
fun registerAppStatusListener(listener: OnAppStatusListener)
this.listener = listener
override fun onActivityPaused(activity: Activity)
currentResumedActivity == null
override fun onActivityStarted(activity: Activity)
activityStartCount++
if (activityStartCount == 1)
listener?.onAppFront()
override fun onActivityDestroyed(activity: Activity) = Unit
override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) = Unit
override fun onActivityStopped(activity: Activity)
activityStartCount--
if (activityStartCount == 0)
listener?.onAppBackground()
override fun onActivityCreated(activity: Activity, bundle: Bundle?) = Unit
override fun onActivityResumed(activity: Activity)
currentResumedActivity = WeakReference(activity)
fun getCurrentActivity(): Activity?
return currentResumedActivity?.get()
是不是感觉代码有点繁琐?需要通过对activity记数来判断应用是否在前后台。那么如果我们通过lifecycle会变成怎样呢?那我们来看一下:
/**
* @date:2021/02/08
* @author:Silence
* @describe:
**/
class AppLifeObserver : LifecycleObserver
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onForeground()
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onBackground()
然后我们在application直接调用如下代码:
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifeObserver())
是不是相对之前的记数方法简单很多。而且通过lifecycle的实现可读性相对而言会更高。
总结
本篇我们简单介绍了lifecycle的使用以及通过尝试使用lifecycle这个歌简单的例子对app前台后做监听。可以发现lifecycle的使用很简单。但是本篇并没有讲到lifecycle的原理。因为你只有会使用了才会愿意了解原理。那么下一篇我们讲lifecycle的实现原理。
参考
本文首发于我的个人博客:Android Jetpack架构组件——Lifecycle使用篇
更多文章请关注我的公众号:码农职场
以上是关于Android Jetpack架构组件(三)—ViewModel的主要内容,如果未能解决你的问题,请参考以下文章
Android Jetpack架构组件——什么是Jetpack?
Android Jetpack架构组件——什么是Jetpack?
Android高级Jetpack架构组件+Jetpack compose强化实战
Android Jetpack架构组件带你了解Android Jetpack