如果没有 @Inject 构造函数或 @Provides- 或 @Produces- 注解的方法,则无法提供 Retrofit

Sin*_*yuk 5 android dependency-injection dagger retrofit dagger-2

我现在正在学习 Dagger 2,在没有代码的情况下解释问题对我来说太痛苦了,所以让我先列出我所有的模块、组件等:


应用程序类

public class App extends Application {

private ApiComponent mApiComponent = null;
private AppComponent mAppComponent = null;

public ApiComponent getApiComponent() {
    if (mApiComponent == null) {
        // Dagger%COMPONENT_NAME%
        mApiComponent = DaggerApiComponent.builder()
                // list of modules that are part of this component need to be created here too
                .appModule(new AppModule(this)) // This also corresponds to the name of your module: %component_name%Module
                .apiModule(new ApiModule(this))
                .build();

    }
    return mApiComponent;
}

public AppComponent getAppComponent() {
    if (mAppComponent == null) {
        // If a Dagger 2 component does not have any constructor arguments for any of its modules,
        // then we can use .create() as a shortcut instead:
        mAppComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(this))
                .build();

    }
    return mAppComponent;
}
}
Run Code Online (Sandbox Code Playgroud)

应用组件

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(RetrofitDemo target);
}
Run Code Online (Sandbox Code Playgroud)

应用程序模块

    private final Application mContext;

AppModule(Application context) {
    mContext = context;
}

@Singleton
@ForApplication
@Provides
Application provideApplication() {
    return mContext;
}

@Singleton
@ForApplication
@Provides
Context provideContext() {
    return mContext;
}
Run Code Online (Sandbox Code Playgroud)

API组件

@Singleton
@Component(dependencies = {AppModule.class},modules =    {ApiModule.class})
public interface ApiComponent {
     void inject(RetrofitDemo target);
}
Run Code Online (Sandbox Code Playgroud)

API模块

@Inject
Context application;

@Inject
public ApiModule(Context context){
    this.application = context;
}

@Provides
@Singleton
Gson provideGson() {
    return new GsonBuilder()
            // All timestamps are returned in ISO 8601 format:
            .setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
            // Blank fields are included as null instead of being omitted.
            .serializeNulls()
            .create();
}


@Provides
@Singleton
OkHttpClient provideOkHttpClient() {
  ...
}



@Provides
@Singleton
public Retrofit provideRetrofit(Gson gson,OkHttpClient okHttpClient){
  return new Retrofit.Builder()
          .baseUrl(DribbleApi.END_POINT)
          .addConverterFactory(GsonConverterFactory.create(gson))
          .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
          .client(okHttpClient)
          .build();
}
Run Code Online (Sandbox Code Playgroud)

我的活动将是这样的:

    @Inject
Retrofit mRetrofit;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_retrofit_demo);
    ((App) getApplication()).getApiComponent().inject(this);
...
Run Code Online (Sandbox Code Playgroud)

这是错误消息:

Error:(18, 10) : retrofit2.Retrofit cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
retrofit2.Retrofit is injected at com.sinyuk.yuk.RetrofitDemo.mRetrofit
com.sinyuk.yuk.RetrofitDemo is injected at com.sinyuk.yuk.AppComponent.inject(target)
Run Code Online (Sandbox Code Playgroud)

让我困惑的是,retrofit 实例是由 ApiModule 提供的,但为什么错误提示说它是在 appComponent 处注入的?而且我在代码中找不到任何错误的地方。T_T,学习 Dagger 对我来说太沉重了……我想。


此外,就我而言,我dependencies = AppModule.class module = ApiModule.class在 AppComponent 中编写,我认为这似乎是正确的,但如果我编写module = ({AppComponent.class,ApiComponent.class}),它也可以正常工作。任何人都可以解释我为什么吗?


请检查我的代码并给我一些建议。提前谢谢!

OYR*_*YRM 5

@Sinyuk 这里有很多东西需要解压,Dagger 乍一看有点复杂,但我想我可以提供帮助。首先,您对注释存在概念上的误解@Component。AComponent是您定义的接口,Dagger 通过代码生成来实现它。您将定义接口并对其进行注释,@Component然后向 Dagger 提供一组Module以在生成过程中使用。您使用的模块是通过注释modules的元素传入的@Component。如果您想让一个Component允许另一个Component支持注入过程,那么您在注入代码时需要 Dagger 使用的任何接口都将通过注释的元素Component传入。dependencies@Component

--

因此,以下说法不正确

@Component(dependencies = AppModule.class  module = ApiModule.class`)
Run Code Online (Sandbox Code Playgroud)

相反,要让一个组件使用两个模块,请编写:

@Component(modules = {ApiModule.class, AppModule.class})
Run Code Online (Sandbox Code Playgroud)

或者,让一个组件使用一个模块并依赖于另一个组件

@Component(modules = {AppModule.class}, dependencies = {ApiComponent.class})
Run Code Online (Sandbox Code Playgroud)

我希望这可以帮助您走上正确的道路。如果您有任何后续问题,请告诉我。