Inject object with @ActivityScope in @ViewScope

2019-07-27 03:30发布

问题:

I'm using dagger 2.11 and it's not possible to inject Views out of the box, but I managed to do so:

BindingModule:

@Module(subcomponents = {...})
public abstract class ViewBindingModule {

    @Binds
    @IntoMap
    @ViewKey(MyView.class)
    abstract AndroidInjector.Factory<? extends BaseView> myView(MyViewSubComponent.Builder builder);
}

MyViewSubComponent:

@Subcomponent(modules = MyViewModule.class)
public interface MyViewSubComponent extends AndroidInjector<MyView> {

    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<MyView> {}
}

MyViewModule:

@Module
public abstract class MyViewModule extends ViewModule<MyView> {

    public MyViewModule(MyView view) {
        super(view);
    }
}

ViewModule:

@Module
public abstract class ViewModule<V extends View> {

    protected final V view;

    public ViewModule(V view) {
        this.view = view;
    }

    @Provides
    @ViewScope
    V provideView() {
        return view;
    }
}

BaseView:

ViewInjection.inject(this);

ViewInjection is pretty much a copy from other Injectors.

Now, I've an Activity, a CustomView and a BaseViewModel. My BaseViewModel contains an Object which needs an instance of AppCompatActivity.

I'm provinding it as fallow:

ActivityBindingModule:

@Module
public abstract class ActivityBindingModule {

    @ActivityScope
    @ContributesAndroidInjector(modules = MyActivityModule.class)
    abstract MyActivity activity();
}

MyActivityModule

@Module
public abstract class MyActivityModule {

    @Binds
    abstract AppCompatActivity activity(MyActivity activity);
}

The object who needs the context:

 @Inject
 public Object(AppCompatActivity activity, ...)

BaseViewModel:

 public BaseViewModel(Object object,...)

ViewModel (extends BaseViewModel):

 @Inject
 public ChildViewModel(Object object,...){super(object,...);...}

This configurations works pretty well when injecting my BaseViewModel inside the Activity (the "View"), but if I want to provide a BaseViewModel to a View (@Inject BaseViewModel inside a BaseView) I'll have a problem because my Object needs an Activity provided by the ActivityBindingModule/MyActivityModule which has @ActivityScope and not @ViewScope:

Error:(27, 1) error: [dagger.android.AndroidInjector.inject(T)] android.support.v7.app.AppCompatActivity cannot be provided without an @Inject constructor or from an @Provides-annotated method.
android.support.v7.app.AppCompatActivity is injected at
com.myapp.MyObject.<init>(activity, …)
com.myapp.MyObject is injected at
com.myapp.MyViewModel.<init>(object, …)
com.myapp.MyViewModel is injected at
com.myapp.MyViewModel.mMyViewModel
com.myapp.MyView is injected at
dagger.android.AndroidInjector.inject(arg0)
A binding with matching key exists in component: com.myapp.di...ActivityBindingModule_MyActivity.MyActivitySubcomponent
...

I don't know if I'm being clear here, a bit confusing perhaps, but how can I achieve this?
Thanks for your time.