Fork me on GitHub

ViewModel 源代码分析 (一)

  • viewmodel

    • CreationExtras
      ViewModel创建过程中传递额外参数的容器。

    • InitializerViewModelFactory

      ViewModelProvider.Factory接口实现类,使用ViewModelInitializer来创建ViewModel实例。

    • InitializerViewModelFactoryBuilder

      用于构建InitializerViewModelFactory的工具,通常以DSL形式提供。

    • MutableCreationExtras

      可变版本的CreationExtras,允许添加或修改额外参数。

    • ViewModelFactoryDsl

      一个DSL(领域特定语言),用于更声明式地定义如何创建ViewModel。

    • ViewModelInitializer

      用于初始化ViewModel的类,通常与ViewModelFactoryDsl一起使用。

    • InitializerViewModelFactory

      提供了使用InitializerViewModelFactory的Kotlin扩展。

  • AndroidViewModel

    AndroidViewModel是ViewModel的一个子类,它接受应用程序的Application作为上下文,这对于需要访问Application资源的ViewModel特别有用。

  • HasDefaultViewModelProviderFactory

    一个接口,标识一个类拥有默认的ViewModelProvider.Factory,用于创建ViewModel。

  • ViewModel

  • ViewModelLazy

    一个提供懒加载ViewModel实例的工具类。

  • ViewModelProvider

    用于获取ViewModel实例,确保配置更改时ViewModel可以持续使用。

  • ViewModelStore

    用于保存ViewModel实例的类,以便它们可以跨配置更改持续存在。

  • ViewModelStoreOwner

    一个接口,标识一个类可以拥有ViewModelStore。

  • ViewTreeViewModelStoreOwner

    用于从视图树中查找ViewModelStoreOwner的工具类。

  • ViewTreeViewModelKt

    提供了操作和查询视图树中ViewModel的Kotlin扩展

CreationExtras 与 MutableCreationExtra

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package androidx.lifecycle.viewmodel


public abstract class CreationExtras internal constructor() {
internal val map: MutableMap<Key<*>, Any?> = mutableMapOf()
public interface Key<T>
public abstract operator fun <T> get(key: Key<T>): T?

object Empty : CreationExtras() {
override fun <T> get(key: Key<T>): T? = null
}
}

/**
* [CreationExtras]的可变实现
*
* @param initialExtras 将被填充到结果MutableCreationExtras中的额外信息
*/
public class MutableCreationExtras(initialExtras: CreationExtras = Empty) : CreationExtras() {

init {
map.putAll(initialExtras.map)
}
/**
* 将给定的[key]与[t]关联
*/
public operator fun <T> set(key: Key<T>, t: T) {
map[key] = t
}

public override fun <T> get(key: Key<T>): T? {
@Suppress("UNCHECKED_CAST")
return map[key] as T?
}
}

fun viewModelFactory 和 InitializerViewModelFactoryBuilder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package androidx.lifecycle.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import kotlin.reflect.KClass

@DslMarker
public annotation class ViewModelFactoryDsl


public inline fun viewModelFactory(
builder: InitializerViewModelFactoryBuilder.() -> Unit
): ViewModelProvider.Factory = InitializerViewModelFactoryBuilder().apply(builder).build()

/**
* 用于构建新的[ViewModelProvider.Factory]的DSL。
*/
@ViewModelFactoryDsl
public class InitializerViewModelFactoryBuilder {
private val initializers = mutableListOf<ViewModelInitializer<*>>()

/**
* 为给定的ViewModel类添加初始化器。
*
* @param clazz 与初始化器关联的类。
* @param initializer 用于创建ViewModel类实例的lambda表达式
*/
fun <T : ViewModel> addInitializer(clazz: KClass<T>, initializer: CreationExtras.() -> T) {
initializers.add(ViewModelInitializer(clazz.java, initializer))
}

fun build(): ViewModelProvider.Factory =
InitializerViewModelFactory(*initializers.toTypedArray())
}

inline fun <reified VM : ViewModel> InitializerViewModelFactoryBuilder.initializer(
noinline initializer: CreationExtras.() -> VM
) {
addInitializer(VM::class, initializer)
}

class ViewModelInitializer<T : ViewModel>(
internal val clazz: Class<T>,
internal val initializer: CreationExtras.() -> T,
)

internal class InitializerViewModelFactory(
private vararg val initializers: ViewModelInitializer<*>
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
var viewModel: T? = null
@Suppress("UNCHECKED_CAST")
initializers.forEach {
if (it.clazz == modelClass) {
viewModel = it.initializer.invoke(extras) as? T
}
}
return viewModel ?: throw IllegalArgumentException(
"No initializer set for given class ${modelClass.name}"
)
}
}

AndroidViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package androidx.lifecycle;

import android.annotation.SuppressLint;
import android.app.Application;

import androidx.annotation.NonNull;

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

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

@SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
@NonNull
public <T extends Application> T getApplication() {
return (T) mApplication;
}
}

AndroidViewModel 是一个扩展了标准 ViewModel 功能的类,通过提供对 Application 上下文的访问,它允许 ViewModel 执行需要这种上下文的操作。使用 AndroidViewModel 可以帮助你编写更清晰、更健壮的应用程序代码,尤其是在处理配置更改和应用程序范围的资源访问时

HasDefaultViewModelProviderFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package androidx.lifecycle;

import androidx.annotation.NonNull;
import androidx.lifecycle.viewmodel.CreationExtras;

public interface HasDefaultViewModelProviderFactory {
@NonNull
ViewModelProvider.Factory getDefaultViewModelProviderFactory();

@NonNull
default CreationExtras getDefaultViewModelCreationExtras() {
return CreationExtras.Empty.INSTANCE;
}
}

ViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package androidx.lifecycle;

import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.Closeable;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

public abstract class ViewModel {
// Can't use ConcurrentHashMap, because it can lose values on old apis (see b/37042460)
@Nullable
private final Map<String, Object> mBagOfTags = new HashMap<>();
@Nullable
private final Set<Closeable> mCloseables = new LinkedHashSet<>();
private volatile boolean mCleared = false;

public ViewModel() {
}

public ViewModel(@NonNull Closeable... closeables) {
mCloseables.addAll(Arrays.asList(closeables));
}

public void addCloseable(@NonNull Closeable closeable) {
if (mCloseables != null) {
synchronized (mCloseables) {
mCloseables.add(closeable);
}
}
}

@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}

@MainThread
final void clear() {
mCleared = true;
if (mBagOfTags != null) {
synchronized (mBagOfTags) {
for (Object value : mBagOfTags.values()) {
closeWithRuntimeException(value);
}
}
}
if (mCloseables != null) {
synchronized (mCloseables) {
for (Closeable closeable : mCloseables) {
closeWithRuntimeException(closeable);
}
}
}
onCleared();
}

@SuppressWarnings("unchecked")
<T> T setTagIfAbsent(String key, T newValue) {
T previous;
synchronized (mBagOfTags) {
previous = (T) mBagOfTags.get(key);
if (previous == null) {
mBagOfTags.put(key, newValue);
}
}
T result = previous == null ? newValue : previous;
if (mCleared) {
closeWithRuntimeException(result);
}
return result;
}

@SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
<T> T getTag(String key) {
if (mBagOfTags == null) {
return null;
}
synchronized (mBagOfTags) {
return (T) mBagOfTags.get(key);
}
}

private static void closeWithRuntimeException(Object obj) {
if (obj instanceof Closeable) {
try {
((Closeable) obj).close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}

举例子说明哪些特殊数据是需要 ViewModel 特别管理的

ViewModel 的使用场景中,有几种特殊数据需要通过 ViewModel 来特别管理,主要是因为这些数据的生命周期需要与 ViewModel 保持一致,或者这些数据在 ViewModel 被销毁时需要进行特殊处理。以下是一些示例:

  1. 网络请求的取消标识(Cancellation Tokens):当使用 ViewModel 进行网络请求时,可以在 mBagOfTags 中保存请求的取消标识(如 Call 对象或其他取消机制)。如果用户离开了关联的界面(例如,Activity 或 Fragment 被销毁),则可以在 ViewModelonCleared() 方法中取消所有挂起的网络请求,以避免不必要的网络流量消耗或潜在的内存泄漏。

  2. 数据库监听器(Database Listeners):如果 ViewModel 监听数据库变化(例如,使用 SQLite 数据库或 Room 持久库),可以将监听器对象存储在 mBagOfTags 中。当 ViewModel 被清理时,这些监听器可以被适当地移除,防止因为监听器持续激活而导致的内存泄漏。

  3. 文件资源(File Resources):应用可能会打开文件进行读写操作,这些文件的句柄或相关的流对象(如 FileInputStreamFileOutputStream)可以放在 mBagOfTags 中。在 ViewModel 生命周期结束时,确保这些资源被正确关闭,避免文件资源泄漏。

  4. 自定义资源的清理(Custom Resource Cleanup):如果有一些自定义的资源或对象需要在 ViewModel 生命周期结束时进行清理(比如自定义的缓存机制、临时文件的删除等),也可以利用 mBagOfTags 来管理这些资源。通过实现 Closeable 接口,可以确保这些资源在 ViewModelclear() 方法被调用时得到正确的处理。

  5. 订阅服务(Subscriptions):当 ViewModel 订阅了某些事件通知或数据流(例如,使用 RxJava 的 Observable 或 LiveData 订阅),可以将这些订阅的取消引用(比如 Disposable)存储在 mBagOfTags 中。这样,可以在不需要这些订阅时或 ViewModel 销毁时,统一取消订阅,防止内存泄漏。

通过以上示例,可以看出 ViewModel 中的 mBagOfTags 提供了一种便捷的方式来管理与 ViewModel 生命周期紧密相关的特殊数据和资源,帮助开发者维护应用的健壮性和性能。

ViewModelLazy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package androidx.lifecycle

import androidx.lifecycle.viewmodel.CreationExtras
import kotlin.reflect.KClass

public class ViewModelLazy<VM : ViewModel> @JvmOverloads constructor(
private val viewModelClass: KClass<VM>,
private val storeProducer: () -> ViewModelStore,
private val factoryProducer: () -> ViewModelProvider.Factory,
private val extrasProducer: () -> CreationExtras = { CreationExtras.Empty }
) : Lazy<VM> {
private var cached: VM? = null

override val value: VM
get() {
val viewModel = cached
return if (viewModel == null) {
val factory = factoryProducer()
val store = storeProducer()
ViewModelProvider(
store,
factory,
extrasProducer()
).get(viewModelClass.java).also {
cached = it
}
} else {
viewModel
}
}

override fun isInitialized(): Boolean = cached != null
}

ViewModelProvider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
@file:JvmName("ViewModelProviderGetKt")

package androidx.lifecycle

import android.app.Application
import androidx.annotation.MainThread
import androidx.annotation.RestrictTo
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.DEFAULT_KEY
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.defaultFactory
import androidx.lifecycle.viewmodel.CreationExtras.Key
import androidx.lifecycle.ViewModelProvider.NewInstanceFactory.Companion.VIEW_MODEL_KEY
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.InitializerViewModelFactory
import androidx.lifecycle.viewmodel.MutableCreationExtras
import androidx.lifecycle.viewmodel.ViewModelInitializer
import java.lang.IllegalArgumentException
import java.lang.RuntimeException
import java.lang.reflect.InvocationTargetException
import kotlin.UnsupportedOperationException

public open class ViewModelProvider

@JvmOverloads
constructor(
private val store: ViewModelStore,
private val factory: Factory,
private val defaultCreationExtras: CreationExtras = CreationExtras.Empty,
) {

public interface Factory {

public fun <T : ViewModel> create(modelClass: Class<T>): T {
throw UnsupportedOperationException(
"Factory.create(String) is unsupported. This Factory requires " +
"`CreationExtras` to be passed into `create` method."
)
}

public fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T =
create(modelClass)

companion object {
@JvmStatic
fun from(vararg initializers: ViewModelInitializer<*>): Factory =
InitializerViewModelFactory(*initializers)
}
}

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public open class OnRequeryFactory {
public open fun onRequery(viewModel: ViewModel) {}
}

public constructor(
owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))

public constructor(owner: ViewModelStoreOwner, factory: Factory) : this(
owner.viewModelStore,
factory,
defaultCreationExtras(owner)
)

@MainThread
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
val canonicalName = modelClass.canonicalName
?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
return get("$DEFAULT_KEY:$canonicalName", modelClass)
}

@Suppress("UNCHECKED_CAST")
@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
val viewModel = store[key]
if (modelClass.isInstance(viewModel)) {
(factory as? OnRequeryFactory)?.onRequery(viewModel)
return viewModel as T
} else {
@Suppress("ControlFlowWithEmptyBody")
if (viewModel != null) {
// TODO: log a warning.
}
}
val extras = MutableCreationExtras(defaultCreationExtras)
extras[VIEW_MODEL_KEY] = key
// AGP has some desugaring issues associated with compileOnly dependencies so we need to
// fall back to the other create method to keep from crashing.
return try {
factory.create(modelClass, extras)
} catch (e: AbstractMethodError) {
factory.create(modelClass)
}.also { store.put(key, it) }
}

// actually there is getInstance()
@Suppress("SingletonConstructor")
public open class NewInstanceFactory : Factory {
@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return try {
modelClass.newInstance()
} catch (e: InstantiationException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: IllegalAccessException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
}
}

public companion object {
private var sInstance: NewInstanceFactory? = null

@JvmStatic
public val instance: NewInstanceFactory
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
get() {
if (sInstance == null) {
sInstance = NewInstanceFactory()
}
return sInstance!!
}

private object ViewModelKeyImpl : Key<String>

@JvmField
val VIEW_MODEL_KEY: Key<String> = ViewModelKeyImpl
}
}

public open class AndroidViewModelFactory
private constructor(
private val application: Application?,
@Suppress("UNUSED_PARAMETER") unused: Int,
) : NewInstanceFactory() {

@Suppress("SingletonConstructor")
public constructor() : this(null, 0)

@Suppress("SingletonConstructor")
public constructor(application: Application) : this(application, 0)

@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
return if (application != null) {
create(modelClass)
} else {
val application = extras[APPLICATION_KEY]
if (application != null) {
create(modelClass, application)
} else {
// For AndroidViewModels, CreationExtras must have an application set
if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
throw IllegalArgumentException(
"CreationExtras must have an application by `APPLICATION_KEY`"
)
}
super.create(modelClass)
}
}
}

@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return if (application == null) {
throw UnsupportedOperationException(
"AndroidViewModelFactory constructed " +
"with empty constructor works only with " +
"create(modelClass: Class<T>, extras: CreationExtras)."
)
} else {
create(modelClass, application)
}
}

@Suppress("DocumentExceptions")
private fun <T : ViewModel> create(modelClass: Class<T>, app: Application): T {
return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
try {
modelClass.getConstructor(Application::class.java).newInstance(app)
} catch (e: NoSuchMethodException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: IllegalAccessException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: InstantiationException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: InvocationTargetException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
}
} else super.create(modelClass)
}

public companion object {
internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
if (owner is HasDefaultViewModelProviderFactory)
owner.defaultViewModelProviderFactory else instance

internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"

private var sInstance: AndroidViewModelFactory? = null

@JvmStatic
public fun getInstance(application: Application): AndroidViewModelFactory {
if (sInstance == null) {
sInstance = AndroidViewModelFactory(application)
}
return sInstance!!
}

private object ApplicationKeyImpl : Key<Application>

@JvmField
val APPLICATION_KEY: Key<Application> = ApplicationKeyImpl
}
}
}

internal fun defaultCreationExtras(owner: ViewModelStoreOwner): CreationExtras {
return if (owner is HasDefaultViewModelProviderFactory) {
owner.defaultViewModelCreationExtras
} else CreationExtras.Empty
}

@MainThread
public inline fun <reified VM : ViewModel> ViewModelProvider.get(): VM = get(VM::class.java)

简单解析一下 ViewModelProvider

在这段代码中,定义了一个ViewModelProvider类,其作用是提供ViewModel实例。
在MVVM架构中,ViewModel是负责准备和管理UI相关数据的组件,它使数据和命令可以轻松地绑定到UI控件,同时保持UI控件和应用逻辑的分离。
ViewModelProvider负责创建和管理这些ViewModel对象。
以下是该代码段中定义的主要函数及其作用的分析:

构造函数

  • ViewModelProvider构造函数: 接收一个ViewModelStore和一个Factory作为参数,以及一个可选的CreationExtras。这些构造函数允许你在创建ViewModelProvider实例时指定ViewModel的存储和创建方式。

内部接口和类

  • Factory接口: 定义了创建ViewModel实例的方法。这个接口允许自定义ViewModel的创建过程,包括通过CreationExtras传递额外的创建参数。
  • OnRequeryFactory: 这是一个可选的回调,当ViewModel被重新查询时调用。
  • NewInstanceFactory: 一个默认的Factory实现,它使用反射来创建ViewModel的新实例。
  • AndroidViewModelFactory: 专门为AndroidViewModel定制的Factory实现,它需要Application实例来创建ViewModel

主要方法

  • get方法: 重载的方法,用于获取指定类的ViewModel实例。如果ViewModel已经存在于ViewModelStore中,则返回这个实例;如果不存在,则通过Factory创建新的实例并存储起来。这些方法确保ViewModel的生命周期被正确管理,即使在配置更改(如屏幕旋转)后也能保持状态。
  • defaultCreationExtras函数: 为ViewModel创建提供默认的CreationExtras。这是用于传递额外参数给ViewModel构造函数的一种机制。

其他重要组件

  • ViewModelStore: 一个容器,用于存储和管理ViewModel实例。这确保了ViewModel能够跨配置更改存活。
  • ViewModelStoreOwner: 一个接口,表示拥有ViewModelStore的对象,通常是UI控制器,如Activity或Fragment。
  • CreationExtras: 一个容器,用于在创建ViewModel时传递额外的参数。它支持通过键值对形式传递任意数据。

整体而言,这段代码提供了一个灵活的机制来创建和管理ViewModel实例,支持自定义创建过程,并确保ViewModel能够有效地与UI组件的生命周期同步。

这段代码体现了Android架构组件中ViewModel的灵活创建和管理机制,包括支持自定义工厂、传递额外参数以及通过工厂模式解耦ViewModel的创建过程。这套机制不仅提高了ViewModel使用的灵活性,还增强了组件之间的解耦,使得应用架构更加清晰和易于维护。

参数 defaultCreationExtras 的作用

defaultCreationExtras函数在ViewModelProvider的上下文中扮演着重要的角色。它提供了一种机制,用于在创建ViewModel实例时传递额外的参数,这些参数被封装在CreationExtras对象中。这允许ViewModel的构造过程中接收来自ViewModelProvider以外的信息,进而使得ViewModel的创建更加灵活和动态。

CreationExtras的作用

CreationExtras是一种键值对集合,它允许开发者在创建ViewModel时传递任意类型的数据。这些数据可以是应用上下文(如Application实例)、配置参数,或者任何对于ViewModel初始化过程中可能需要的信息。

defaultCreationExtras 使用场景

defaultCreationExtras的使用场景通常涉及到需要向ViewModel传递额外信息的情况。例如,如果某个ViewModel需要访问全局的应用状态,或者依赖于特定的服务实例,这些依赖项可以通过CreationExtras在创建时传递给ViewModel,而defaultCreationExtras函数就是为了方便地提供这类默认参数的。

总之,defaultCreationExtras函数和CreationExtras机制为ViewModel的创建提供了额外的灵活性和动态配置能力,使得ViewModel能够更好地适应不同的应用场景和需求。

,