I am trying to replicate what ViewModelFactory does for my presenter classes, Here is my Dagger2 Code
public class App extends DaggerApplication { //Support import
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerAppComponent.builder().create(this);
}
}
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@MapKey
public @interface PresenterKey {
Class<? extends PresenterClass> value();
}
@Module
public abstract class PresenterModule {
@Binds
@IntoMap
@PresenterKey(AuthPresenterImpl.class)
abstract PresenterClass bindsAuthPresenterImpl(AuthPresenterImpl authViewModel);
@Binds
abstract PresenterFactory bindsPresenterFactory(PresenterFactory viewModelFactory);
}
@Singleton
public class PresenterFactory {
private final Map<Class<? extends PresenterClass>, Provider<PresenterClass>> creators;
@Inject
public PresenterFactory(Map<Class<? extends PresenterClass>, Provider<PresenterClass>> creators) {
this.creators = creators;
}
@SuppressWarnings("unchecked")
public <T extends PresenterClass> T create(Class<T> modelClass) {
Provider<? extends PresenterClass> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class<? extends PresenterClass>, Provider<PresenterClass>> entry : creators.entrySet()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getValue();
break;
}
}
}
if (creator == null) {
throw new IllegalArgumentException("unknown model class " + modelClass);
}
try {
return (T) creator.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
When i try to build i get error as
import in.silentsudo.authflow.di.modules.DaggerAppComponent;
^
symbol: class DaggerAppComponent
location: package in.silentsudo.authflow.di.modules
/path/to/project/app/src/main/java/in/silentsudo/authflow/di/modules/AppComponent.java:17: error: [Dagger/BindingCycle] [dagger.android.AndroidInjector.inject(T)] Found a dependency cycle:
public interface AppComponent extends AndroidInjector<AuthFlow> {
^
in.silentsudo.authflow.viewmodels.PresenterFactory is injected at
in.silentsudo.authflow.di.modules.PresenterModule.bindsPresenterFactory(presenterFactory)
in.silentsudo.authflow.viewmodels.PresenterFactory is injected at
in.silentsudo.authflow.AbstractActivity.factory
in.silentsudo.authflow.auth.AuthActivity is injected at
dagger.android.AndroidInjector.inject(T)
component path: in.silentsudo.authflow.di.modules.AppComponent ? in.silentsudo.authflow.di.modules.ActivityModule_BindsAuthActivity.AuthActivitySubcomponent
2 errors
Is there anything wrong i may be doing/anything silly, please help,
EDITED:
Concrete class
public class AuthPresenterImpl extends AbstractPresenter {
@Inject
public AuthPresenterImpl(AuthApi api) {
}
}
Here is your dependency cycle:
@Binds
@IntoMap
@PresenterKey(PresenterClass.class)
abstract PresenterClass bindsAuthPresenterClass(PresenterClass authViewModel);
You must pass a concrete implementation like such:
@Binds
@IntoMap
@PresenterKey(ConcretePresenterClass.class)
abstract PresenterClass bindsAuthPresenterClass(ConcretePresenterClass authViewModel);
I managed to solve this, the dependency issue was at this line
@Binds
abstract PresenterFactory bindsPresenterFactory(PresenterFactory viewModelFactory);
Here i needed to return a reference and provide a concrete implementer of that reference. Working changes are below:
public interface PresenterFactory {
/**
* Creates a new instance of the given {@code Class}.
* <p>
*
* @param modelClass a {@code Class} whose instance is requested
* @param <T> The type parameter for the ViewModel.
* @return a newly created ViewModel
*/
@NonNull
<T extends PresenterClass> T create(@NonNull Class<T> modelClass);
}
Concrete implementer
@Singleton
public class PresenterFactoryImpl implements PresenterFactory {
private final Map<Class<? extends PresenterClass>, Provider<PresenterClass>> creators;
@Inject
public PresenterFactoryImpl(Map<Class<? extends PresenterClass>, Provider<PresenterClass>> creators) {
this.creators = creators;
}
@SuppressWarnings("unchecked")
@Override
public <T extends PresenterClass> T create(Class<T> modelClass) {
Provider<? extends PresenterClass> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class<? extends PresenterClass>, Provider<PresenterClass>> entry : creators.entrySet()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getValue();
break;
}
}
}
if (creator == null) {
throw new IllegalArgumentException("unknown model class " + modelClass);
}
try {
return (T) creator.get();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
and how to define it in PresenterModule
@Module
public abstract class PresenterModule {
@Binds
@IntoMap
@PresenterKey(AuthPresenterImpl.class)
abstract PresenterClass bindsAuthPresenterImpl(AuthPresenterImpl authViewModel);
@Binds
abstract PresenterFactory bindsPresenterFactory(PresenterFactoryImpl viewModelFactory);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.