1 /*
<lambda>null2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package androidx.lifecycle.viewmodel
18
19 import androidx.lifecycle.ViewModel
20 import androidx.lifecycle.ViewModelProvider
21 import androidx.lifecycle.ViewModelStore
22 import androidx.lifecycle.viewmodel.internal.SynchronizedObject
23 import androidx.lifecycle.viewmodel.internal.ViewModelProviders
24 import androidx.lifecycle.viewmodel.internal.synchronized
25 import kotlin.reflect.KClass
26
27 /**
28 * Internal implementation of the multiplatform [ViewModelProvider].
29 *
30 * Kotlin Multiplatform does not support expect class with default implementation yet, so we
31 * extracted the common logic used by all platforms to this internal class.
32 *
33 * @see <a href="https://youtrack.jetbrains.com/issue/KT-20427">KT-20427</a>
34 */
35 internal class ViewModelProviderImpl(
36 private val store: ViewModelStore,
37 private val factory: ViewModelProvider.Factory,
38 private val defaultExtras: CreationExtras,
39 ) {
40
41 private val lock = SynchronizedObject()
42
43 @Suppress("UNCHECKED_CAST")
44 internal fun <T : ViewModel> getViewModel(
45 modelClass: KClass<T>,
46 key: String = ViewModelProviders.getDefaultKey(modelClass),
47 ): T {
48 return synchronized(lock) {
49 val viewModel = store[key]
50 if (modelClass.isInstance(viewModel)) {
51 if (factory is ViewModelProvider.OnRequeryFactory) {
52 factory.onRequery(viewModel!!)
53 }
54 return@synchronized viewModel as T
55 }
56
57 val modelExtras = MutableCreationExtras(defaultExtras)
58 modelExtras[ViewModelProvider.VIEW_MODEL_KEY] = key
59
60 return@synchronized createViewModel(factory, modelClass, modelExtras).also { vm ->
61 store.put(key, vm)
62 }
63 }
64 }
65 }
66
67 /**
68 * Returns a new instance of a [ViewModel].
69 *
70 * **Important:** Android targets using `compileOnly` dependencies may encounter AGP desugaring
71 * issues where `Factory.create` throws an `AbstractMethodError`. This is resolved by an
72 * Android-specific implementation that first attempts all `ViewModelProvider.Factory.create` method
73 * overloads before allowing the exception to propagate.
74 *
75 * @see <a href="https://b.corp.google.com/issues/230454566">b/230454566</a>
76 * @see <a href="https://b.corp.google.com/issues/341792251">b/341792251</a>
77 * @see <a href="https://github.com/square/leakcanary/issues/2314">leakcanary/issues/2314</a>
78 * @see <a href="https://github.com/square/leakcanary/issues/2677">leakcanary/issues/2677</a>
79 */
createViewModelnull80 internal expect fun <VM : ViewModel> createViewModel(
81 factory: ViewModelProvider.Factory,
82 modelClass: KClass<VM>,
83 extras: CreationExtras,
84 ): VM
85