Search code examples
androidcoroutineandroid-viewmodelkotlin-delegate

Android Obtain ViewModelScope so it can be used in interface delegation


My viewModel implements an interface by delegation like this:

class ProductViewModel(item: Product) : ViewModel(), ItemInterface by ItemDelegator(item)

Now, inside ItemDelegator I need a CoroutineScope bound to the ViewModel

I simply cannot do ItemInterface by ItemDelegator(viewModelScope, item). When the ViewModel is being created I cannot have a reference to the viewModelScope

1 - Can I somehow "pass" the viewModelScope to the ItemDelegator 2 - Most of my viewModels lifecycle are bound to the activity lifecycle. Is it ok to pass to the ViewModel the activity lifecycleOwner (can obtain lifecycleScope from it) and now, since it is a param in the constructor, I can pass it to the ItemDelegator?


Solution

  • You can reference delegating objects only if they're an argument of primary constructor. By creating them inline (like you) reference is held in an internal field generated during compilation and cannot be accessed.

    You can make your primary constructor private and create secondary constructor that will create your delegator since you don't want to expose your delegate initialization.

    You also need to modify your delegator class so you can lazily inject the scope into it after super ViewModel constructors finishes executing:

    class ItemDelegator(val item : Product) : ItemInterface {
        lateinit var scope : CoroutineScope
    
        ...
    }
    
    class ProductViewModel private constructor(
        item: Product, 
        private val delegate : ItemDelegator
    ) : ViewModel(), ItemInterface by delegate {
    
        constructor(item: Product) : this(ItemDelegator(item))
        init {
            delegate.scope = viewModelScope
        }
    
        ...
    }