Inject presenter into activity via Dagger

2019-07-21 00:08发布

I want to know how to inject Presenter in activity using code Following are details

Following is error message:

 Error:(12, 46) error: cannot find symbol class DaggerCategoryPresenterComponent
Error:(9, 46) error: cannot find symbol class DaggerNetComponent
Error:(18, 10) error: [Dagger/MissingBinding] com.headytest.android.category_listing.CategoryContract.CategoryPresenter cannot be provided without an @Provides-annotated method.
com.headytest.android.category_listing.CategoryContract.CategoryPresenter is injected at
com.headytest.android.MainActivity.categoryPresenter
com.headytest.android.MainActivity is injected at
com.headytest.android.dagger_component.NetComponent.inject(com.headytest.android.MainActivity)

Following are modules

  @Module
  public class NetworkModule {

String baseURL;

public NetworkModule(String baseURL) {
    this.baseURL = baseURL;
}

@Provides
@Singleton
Cache provideHttpCache(Application application) {
    int cacheSize = 10 * 1024 * 1024;
    Cache cache = new Cache(application.getCacheDir(), cacheSize);
    return cache;
}

@Provides
@Singleton
Gson provideGson() {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
    return gsonBuilder.create();
}

@Provides
@Singleton
OkHttpClient provideOkhttpClient(Cache cache) {
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient.Builder client = new OkHttpClient.Builder();
    client.cache(cache);
    client.addInterceptor(interceptor);
    return client.build();
}

@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
    try {
        return new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(baseURL)
                .client(okHttpClient)
                .build();
    } catch (Exception e) {
        e.printStackTrace();
        return new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(Constants.BASE_URL)
                .client(okHttpClient)
                .build();
    }
}
}

ApplicationModule

@Module
public class ApplicationModule {

Application application;

public ApplicationModule(Application application) {
    this.application = application;
}

@Provides
@Singleton
Application providesApplication() {
    return application;
}
}

CategoryContractModule

@Module
public class CategoryContractModule {


public CategoryContractModule() {
}

@Provides
@AScope
CategoryContract.CategoryPresenter providesCategoryPresenter(CategoryPresenterImpl categoryPresenter) {
    return (CategoryContract.CategoryPresenter)categoryPresenter;
}
}

Following are components:

@Singleton
@Component(modules = {ApplicationModule.class, NetworkModule.class})
public interface NetComponent {
void inject(MainActivity activity);
 }

CategoryPresenterComponent:

@AScope
@Component(dependencies = NetComponent.class, modules = 
{CategoryContractModule.class})
public interface CategoryPresenterComponent {
 void inject(MainActivity activity);
 }

AScope

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface AScope {
}

Following is the code in MainActivity:

@Inject
CategoryPresenter categoryPresenter;

@Inject
Retrofit retrofit;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
     DaggerCategoryPresenterComponent.builder()
            .categoryContractModule(new CategoryContractModule())
            .netComponent(((App) getApplicationContext()).getNetComponent())
            .build()
            .inject(this);
}

CategoryPresenterImpl

    public class CategoryPresenterImpl implements CategoryContract.CategoryPresenter {

    @Inject
    public CategoryPresenterImpl() {
    }

    @Override
    public void onStart() {

    }

    @Override
    public void onStop() {

    }

    @Override
    public void getCategoryLiast() {


    }
}

1条回答
迷人小祖宗
2楼-- · 2019-07-21 00:43

I assume current error will be easy to fix, because it very much looks like this issue.

You've instructed Dagger how to provide @AScope CategoryContract.CategoryPresenter but in activity you request Dagger to inject CategoryContract.CategoryPresenter. Dagger is confused at this point, because those two things do not match.

What you have to do, is simply add @AScope to categoryPresenter:

@Inject
@AScope
CategoryPresenter categoryPresenter;

I've checked out your project. The problem was in NetComponent.java:

@Singleton
@Component(modules = {ApplicationModule.class, NetworkModule.class})
public interface NetComponent {
    void inject(MainActivity activity);
}

The issue is in line void inject(MainActivity activity). Why is this an issue? Because by the time you construct NetComponent in App, dagger analyzes MainActivity for @Inject annotated field and sees CategoryPresenter. This means, that at this point Dagger should find appropriate provider/binder method in order to be able to inject MainActivity as declared inside this interface.

But it cannot find such a provider/binder method, because it is declared in an another component - CategoryPresenterComponent and this component (NetComponent) is not connected with CategoryPresenterComponent anyhow (subcomponents or component dependencies), thus bindings are not exposed.

Simply removing that line will make your build successful:

@Singleton
@Component(modules = {ApplicationModule.class, NetworkModule.class})
public interface NetComponent {
}

For resolving "Error:cannot access Nullable" refer to this thread, which suggest applying compile 'com.google.code.findbugs:jsr305:3.0.2' to your gradle file.

After doing this you'll overcome that error message and will stumble on retrofit2.Retrofit cannot be provided without an @Inject constructor or an @Provides-annotated method, which has the same symptoms as CategoryPresenter had.

To overcome this issue you have to add a Retrofit provider method inside NetComponent (or to remove @Inject Retrofit retrofit from activity):

@Singleton
@Component(modules = {ApplicationModule.class, NetworkModule.class})
public interface NetComponent {
    Retrofit providesRetrofit();
}

After doing this you'll be able to run the app, but you'll end up in a NPE in MainActivity, because of this line:

.categoryContractModule(new CategoryContractModule(retrofit.create(HeadyAPI.class)))

You are referring to retrofit object, which is not yet initialized.

Long story short, your initial question has mutated a couple of times and in fact you had a few problems in your code. Still you have a problem there, because you are trying to use retrofit in order to construct a component, that was supposed to inject the retrofit for you.

查看更多
登录 后发表回答