Skip to content
This repository has been archived by the owner on Oct 17, 2023. It is now read-only.

@ContributesAndroidInjector, custom scope and @AssistedInject issue #127

Closed
Suet opened this issue Dec 11, 2019 · 5 comments · Fixed by #167
Closed

@ContributesAndroidInjector, custom scope and @AssistedInject issue #127

Suet opened this issue Dec 11, 2019 · 5 comments · Fixed by #167

Comments

@Suet
Copy link

Suet commented Dec 11, 2019

Hello.
I want to use lifecycle-viewmodel-savedstate in my project, so I came across AssistedInject and decided to use it.
But regardless of all my efforts to mix it with my current project stucture I get compiler errors all the time.
Everything compiles and works fine if I don't use @AssistedInject, @AssistedInject.Factory and ViewModelAssistedFactoriesModule.
But as a result I obviously can't use "@assisted SavedStateHandle savedStateHandle" which was the main goal of all this.
So is it possible to use @AssistedInject with all this @ContributesAndroidInjector and @AuthScope stuff?

Here is my simple configuration:

@Singleton
@Component(modules = [AndroidSupportInjectionModule::class, 
			AppModule::class, 
			ActivityBuildersModule::class,
			ViewModelFactoryModule::class, 
			ViewModelAssistedFactoriesModule::class])
interface AppComponent : AndroidInjector<App> {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun context(context: Context): Builder
        fun build(): AppComponent
    }
}

AppModule provides global @singleton dependencies like, for example, Context and so on.

@Module
internal abstract class ActivityBuildersModule : BaseActivityBuildersModule() {
    @MainScope
    @ContributesAndroidInjector(modules = [MainFragmentBuildersModule::class, MainViewModelsModule::class, MainModule::class])
    internal abstract fun contributeMainActivity(): MainActivity
}

@Module
public abstract class BaseActivityBuildersModule {
    @AuthScope
    @ContributesAndroidInjector(
            modules = {AuthViewModelsModule.class, AuthModule.class} //this is important, because AuthModule provides @AuthScope scoped dependencies
    )
    abstract AuthActivity contributeAuthActivity();
}

@Module
public abstract class AuthViewModelsModule {

    @Binds
    @IntoMap
    @ViewModelKey(AuthActivityVM.class)
    public abstract ViewModelAssistedFactory<? extends ViewModel> bindAuthActivityViewModel(AuthActivityVM.Factory viewModelFactory);

    @Binds
    abstract SavedStateRegistryOwner bindSavedStateRegistryOwner(AuthActivity activity);

    @Nullable
    @Provides
    static Bundle provideDefaultArgs() {
        return null;
    }
}

public interface ViewModelAssistedFactory<T extends ViewModel> {
    T create(SavedStateHandle savedStateHandle);
}
@Module
public class AuthModule {

    @Provides
    @AuthScope
    static LoginValidator provideLoginValidator(){
        return new AuthValidator();
    }
//
//and other @AuthScope things
//
}
@Module
abstract class ViewModelFactoryModule {
    @Binds
    abstract fun bindViewModelFactory(viewModelFactory: ViewModelProviderFactory): ViewModelProvider.Factory
}

@AssistedModule
@Module(includes = {AssistedInject_ViewModelAssistedFactoriesModule.class})
public abstract class ViewModelAssistedFactoriesModule {
}

public class AuthActivityVM extends ViewModel {
    @AssistedInject.Factory
    public interface Factory extends ViewModelAssistedFactory<AuthActivityVM>{}

    @AssistedInject
    //@Inject
    AuthActivityVM(@Assisted SavedStateHandle savedStateHandle,
                   @NonNull Context context, //no complier complains
		   ... //other @Singleton dependencies (also fine)
		   @NonNull LoginValidator loginValidator, **//loginValidator comes from AuthModule and it is scoped with @AuthScpoe** 
                   ...// oter things
		){
	...
}	
}

In AuthActivity I have this bit of code:

    @Inject
    ViewModelProviderFactory providerFactory;

But compiler complains:

com.alidi.base.models.auth.LoginValidator cannot be provided without an @Provides-annotated method.
javax.inject.Provider<com.alidi.base.models.auth.LoginValidator> is injected at
com.alidi.base.ui.auth.AuthActivityVM_AssistedFactory(…, loginValidator, …)

@davidliu
Copy link

davidliu commented Jan 7, 2020

I'm guessing you're using the multibinds ViewModelFactory pattern, where you've got an omni factory made at the @Singleton level that can create all the other ones. Don't do that. The omni-factory, since it lives at the @Singleton level, requires all the dependencies to be filled at that level, and it can't get the @AuthScope dependencies.

Instead of using the multibind factory stuff, just directly get the factory of the vm you need and use that.

@davidliu
Copy link

davidliu commented Jan 7, 2020

Also, this issue should be closed, as it's not really related to AssistedInject at all, just a bog-standard Dagger question.

@Suet
Copy link
Author

Suet commented Jan 8, 2020

Hello.
As I mentioned at the very beginnig "Everything compiles and works fine if I don't use @AssistedInject, @AssistedInject.Factory and ViewModelAssistedFactoriesModule."

@davidliu
Copy link

davidliu commented Jan 8, 2020

Yes, but you wanted to use @AssistedInject right? So I don't see why that's relevant.

@Suet
Copy link
Author

Suet commented Jan 8, 2020

That's exactly what my question was about. I wondered if the code working fine without assisted inject library should still work if I use it and amend a code accordingly. As far as I see there is not much changed in a code. But something breaks and it stops to compile.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants