airbnb / mavericks

Mavericks: Android on Autopilot
https://airbnb.io/mavericks/
Apache License 2.0
5.85k stars 499 forks source link

How to adapt the hellodagger example for an Anvil multi-module project? #638

Closed oheyadam closed 2 years ago

oheyadam commented 2 years ago

I might be slightly confused here, but I've been trying to figure this out for hours. The DaggerMavericksViewModelFactory access the appComponent to get viewModelFactories(), which means it has to live in the :app module, but that means that ViewModels in feature modules can't access the DaggerMavericksViewModelFactory class or daggerMavericksViewModelFactory() function.

You can't move this class to the feature modules either because then it won't have access to the Application class to reference the AppComponent. How to make this work?

gpeal commented 2 years ago

At Tonal, this is what we have:

class DaggerMavericksViewModelFactory<VM : TonalViewModel<S>, S : MavericksState>(
    private val viewModelClass: Class<VM>,
) : MavericksViewModelFactory<VM, S> {
    override fun create(viewModelContext: ViewModelContext, state: S): VM {
        val bindings = when (viewModelContext) {
            is FragmentViewModelContext -> viewModelContext.fragment.bindings<LibUiBindings>()
            else -> viewModelContext.activity.bindings<LibUiBindings>()
        }
        val viewModelFactory = bindings.viewModelFactories()[viewModelClass] ?: error("Unable to find factory for ${viewModelClass.simpleName}")
        val castedViewModelFactory = viewModelFactory.cast<TonalViewModelFactory<VM, S>>()
        return castedViewModelFactory.create(state)
    }
}

where Context/Fragment.bindings<T> can get your Dagger component and cast it to type T

and

interface LibUiBindings {
    fun viewModelFactories(): Map<Class<out TonalViewModel<*>>, TonalViewModelFactory<*, *>>
}

which AppComponent implements.

We also use Anvil to further simplify our multi-module dagger setup but let me know if that helps.

oheyadam commented 2 years ago

Thank you very much. This was definitely helpful!