Last active
March 24, 2025 00:21
-
-
Save volo-droid/54d4443c28ec92ecb0a0741d16d4c47c to your computer and use it in GitHub Desktop.
ViewModel delegates for Toothpick injection library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Copyright (c) 2025 Volodymyr Galandzij | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| import androidx.activity.ComponentActivity | |
| import androidx.activity.viewModels | |
| import androidx.fragment.app.Fragment | |
| import androidx.fragment.app.activityViewModels | |
| import androidx.fragment.app.viewModels | |
| import androidx.lifecycle.ViewModel | |
| import androidx.lifecycle.ViewModelProvider | |
| import androidx.lifecycle.ViewModelStoreOwner | |
| import androidx.lifecycle.viewmodel.CreationExtras | |
| import androidx.lifecycle.viewmodel.initializer | |
| import androidx.lifecycle.viewmodel.viewModelFactory | |
| import toothpick.Scope | |
| import toothpick.Toothpick | |
| // ---------------------- | |
| // Fragment.viewModelOf | |
| // ---------------------- | |
| inline fun <reified VM : ViewModel> Fragment.viewModelOf( | |
| noinline constructor: () -> VM, | |
| noinline ownerProducer: () -> ViewModelStoreOwner = { this }, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| viewModelOf(ownerProducer, extrasProducer) { constructor() } | |
| inline fun <reified VM : ViewModel, reified T1> Fragment.viewModelOf( | |
| noinline constructor: (T1) -> VM, | |
| noinline ownerProducer: () -> ViewModelStoreOwner = { this }, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| viewModelOf(ownerProducer, extrasProducer) { constructor(get()) } | |
| inline fun <reified VM : ViewModel, reified T1, reified T2> Fragment.viewModelOf( | |
| noinline constructor: (T1, T2) -> VM, | |
| noinline ownerProducer: () -> ViewModelStoreOwner = { this }, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| viewModelOf(ownerProducer, extrasProducer) { constructor(get(), get()) } | |
| inline fun <reified VM : ViewModel, reified T1, reified T2, reified T3> Fragment.viewModelOf( | |
| noinline constructor: (T1, T2, T3) -> VM, | |
| noinline ownerProducer: () -> ViewModelStoreOwner = { this }, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| viewModelOf(ownerProducer, extrasProducer) { constructor(get(), get(), get()) } | |
| // ------------------------------ | |
| // Fragment.activityViewModelOf | |
| // ------------------------------ | |
| inline fun <reified VM : ViewModel> Fragment.activityViewModelOf( | |
| noinline constructor: () -> VM, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| activityViewModelOf(extrasProducer) { constructor() } | |
| inline fun <reified VM : ViewModel, reified T1> Fragment.activityViewModelOf( | |
| noinline constructor: (T1) -> VM, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| activityViewModelOf(extrasProducer) { constructor(get()) } | |
| inline fun <reified VM : ViewModel, reified T1, reified T2> Fragment.activityViewModelOf( | |
| noinline constructor: (T1, T2) -> VM, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| activityViewModelOf(extrasProducer) { constructor(get(), get()) } | |
| inline fun <reified VM : ViewModel, reified T1, reified T2, reified T3> Fragment.activityViewModelOf( | |
| noinline constructor: (T1, T2, T3) -> VM, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| activityViewModelOf(extrasProducer) { constructor(get(), get(), get()) } | |
| // ------------------------------- | |
| // ComponentActivity.viewModelOf | |
| // ------------------------------- | |
| inline fun <reified VM : ViewModel> ComponentActivity.viewModelOf( | |
| noinline constructor: () -> VM, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| viewModelOf(extrasProducer) { constructor() } | |
| inline fun <reified VM : ViewModel, reified T1> ComponentActivity.viewModelOf( | |
| noinline constructor: (T1) -> VM, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| viewModelOf(extrasProducer) { constructor(get()) } | |
| inline fun <reified VM : ViewModel, reified T1, reified T2> ComponentActivity.viewModelOf( | |
| noinline constructor: (T1, T2) -> VM, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| viewModelOf(extrasProducer) { constructor(get(), get()) } | |
| inline fun <reified VM : ViewModel, reified T1, reified T2, reified T3> ComponentActivity.viewModelOf( | |
| noinline constructor: (T1, T2, T3) -> VM, | |
| noinline extrasProducer: (() -> CreationExtras)? = null | |
| ): Lazy<VM> = | |
| viewModelOf(extrasProducer) { constructor(get(), get(), get()) } | |
| // --------- | |
| // Helpers | |
| // --------- | |
| inline fun <reified VM : ViewModel> Fragment.viewModelOf( | |
| noinline ownerProducer: () -> ViewModelStoreOwner, | |
| noinline extrasProducer: (() -> CreationExtras)? = null, | |
| noinline viewModelProducer: (Scope.() -> VM) | |
| ): Lazy<VM> = | |
| viewModels(ownerProducer, extrasProducer) { | |
| viewModelFactory(viewModelProducer) { scopeName -> | |
| Toothpick.openScopes(requireActivity().application, scopeName) | |
| } | |
| } | |
| inline fun <reified VM : ViewModel> Fragment.activityViewModelOf( | |
| noinline extrasProducer: (() -> CreationExtras)? = null, | |
| noinline injectedViewModelProducer: (Scope.() -> VM) | |
| ): Lazy<VM> = | |
| activityViewModels(extrasProducer) { | |
| viewModelFactory(injectedViewModelProducer) { scopeName -> | |
| Toothpick.openScopes(requireActivity().application, scopeName) | |
| } | |
| } | |
| inline fun <reified VM : ViewModel> ComponentActivity.viewModelOf( | |
| noinline extrasProducer: (() -> CreationExtras)? = null, | |
| crossinline viewModelProducer: (Scope.() -> VM) | |
| ): Lazy<VM> = | |
| viewModels(extrasProducer) { | |
| viewModelFactory(viewModelProducer) { scopeName -> | |
| Toothpick.openScopes(application, scopeName) | |
| } | |
| } | |
| inline fun <reified VM : ViewModel> viewModelFactory( | |
| crossinline viewModelProducer: (Scope.() -> VM), | |
| scopeName: Any = VM::class.java, | |
| crossinline openScopeBlock: (name: Any) -> Scope | |
| ): ViewModelProvider.Factory = | |
| viewModelFactory { | |
| initializer { | |
| val scope = openScopeBlock(scopeName) | |
| scope.viewModelProducer().apply { | |
| Toothpick.inject(this, scope) | |
| addCloseable { | |
| Toothpick.closeScope(scopeName) | |
| } | |
| } | |
| } | |
| } | |
| inline fun <reified T> Scope.get(): T = getInstance(T::class.java) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class MyViewModel( | |
| private val injectedService1: MyInjectedService1, | |
| private val injectedService2: MyInjectedService2 | |
| ) : ViewModel() | |
| class MySharedViewModel( | |
| private val injectedFooRepository: FooRepository | |
| ) : ViewModel() | |
| class MainFragment : Fragment() { | |
| private val viewModel by viewModelOf(::MyViewModel) | |
| private val sharedViewModel by activityViewModelOf(::MySharedViewModel) | |
| // … | |
| } | |
| class MainActivity : AppCompatActivity() { | |
| // Activity and Fragment will share the same instance of MySharedViewModel | |
| private val sharedViewModel by viewModelOf(::MySharedViewModel) | |
| // … | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you would like to inject
ViewModelvia Toothpick binding you can use:That would allow ViewModel constructor to take
ProviderorLazyas parameters.Keep in mind it'd require either to register an explicit Toothpick binding or mark the ViewModel's constructor with
@Injector@InjectConstructorannotation so that Toothpick generates a Factory for the class.