Dagger2,为Retrofit实例提供不同的URL

Orb*_*bit 3 android dependency-injection dagger-2

目前我正在使用Dagger 2注入一个Retrofit实例,用于小部件中的api调用.根据我的理解,Dagger使用该类型搜索要注入的内容,因此@Provides Retrofit providesRetrofit()使用不同的名称单独声明2 将无效.

继承我目前的代码:

模块:

@Module
public class ApiModule {

    @Provides
    @Singleton
    GsonConverterFactory provideGson() {
        return GsonConverterFactory.create();
    }

    @Provides
    @Singleton
    RxJavaCallAdapterFactory provideRxCallAdapter() {
        return RxJavaCallAdapterFactory.create();
    }

    @Singleton
    @Provides
    Retrofit providePictureRetrofit(GsonConverterFactory gsonConverterFactory, RxJavaCallAdapterFactory rxJavaCallAdapterFactory) {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(MarsWeatherWidget.PICTURE_URL)
                .addConverterFactory(gsonConverterFactory)
                .addCallAdapterFactory(rxJavaCallAdapterFactory)
                .build();
        return retrofit;
    }

....
//Here is the other Retrofit instance where I was wanting to use a different URL.

//    @Singleton
//    @Provides
//    Retrofit provideWeatherRetrofit(GsonConverterFactory gsonConverterFactory, RxJavaCallAdapterFactory rxJavaCallAdapterFactory) {
//        Retrofit retrofit = new Retrofit.Builder()
//                .baseUrl(MarsWeatherWidget.WEATHER_URL)
//                .addConverterFactory(gsonConverterFactory)
//                .addCallAdapterFactory(rxJavaCallAdapterFactory)
//                .build();
//        return retrofit;
//    }
}
Run Code Online (Sandbox Code Playgroud)

零件:

@Singleton
@Component(modules = ApiModule.class)
public interface ApiComponent {

    void inject (MarsWeatherWidget marsWeatherWidget);

}
Run Code Online (Sandbox Code Playgroud)

课程延伸Application:

public class MyWidget extends Application {

    ApiComponent mApiComponent;

    @Override
    public void onCreate() {
        super.onCreate();

        mApiComponent = DaggerApiComponent.builder().apiModule(new ApiModule()).build();
    }

    public ApiComponent getApiComponent() {
        return mApiComponent;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后我真正注入它的地方:

@Inject Retrofit pictureRetrofit;

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // There may be multiple widgets active, so update all of them
        mAppWidgetIds = appWidgetIds;
        ((MyWidget) context.getApplicationContext()).getApiComponent().inject(this);
        final int N = appWidgetIds.length;
        for (int i = 0; i < N; i++) {
            updateAppWidget(context, appWidgetManager, appWidgetIds[i]);
        }
    }

......
//use the injected Retrofit instance to make a call
Run Code Online (Sandbox Code Playgroud)

那么我该如何组织它来为我提供一个单独的Retrofit实例,该实例是使用不同的URL构建的,用于命中不同的API?如果需要更多信息,请与我们联系.

Dav*_*jak 18

提供相同类型的不同版本

您可以使用@Named(或带有注释的自定义注释@Qualifier)来区分相同类型的变体.

添加如下注释:

@Singleton
@Provides
@Named("picture")
Retrofit providePictureRetrofit(GsonConverterFactory gsonConverterFactory, RxJavaCallAdapterFactory rxJavaCallAdapterFactory) {
    return retrofit = new Retrofit.Builder()
            .baseUrl(MarsWeatherWidget.PICTURE_URL) // one url
            .build();
}


@Singleton
@Provides
@Named("weather")
Retrofit provideWeatherRetrofit(GsonConverterFactory gsonConverterFactory, RxJavaCallAdapterFactory rxJavaCallAdapterFactory) {
    return retrofit = new Retrofit.Builder()
            .baseUrl(MarsWeatherWidget.WEATHER_URL) // other url
            .build();
}
Run Code Online (Sandbox Code Playgroud)

习惯 @Qualifier

您还可以创建一个自定义注释,如下所示:

@Qualifier
@Retention(RUNTIME)
public @interface Picture {}
Run Code Online (Sandbox Code Playgroud)

你只需使用它而不是@Named(String).

注入合格版本

当您的模块提供限定类型时,您只需要在需要依赖项的位置添加限定符.

MyPictureService provideService(@Named("picture") Retrofit retrofit) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)


小智 5

您应该使用限定符注释来区分具有相同类型的不同对象——例如区分Retrofit图片和Retrofit天气。

您将相同的限定符应用于@Provides方法和@Inject参数(构造函数或方法参数,或字段)。

@Named是一个限定符注释,但使用它意味着您必须记住在提供点和所有注入点使用完全相同的字符串。(很容易打错@Named("whether")某处。)

但是定义自己的限定符注释很容易。只需定义一个自定义注释类型,并使用以下注释@Qualifier

@Documented
@Qualifier
public @interface Picture {}

@Documented
@Qualifier
public @interface Weather {}
Run Code Online (Sandbox Code Playgroud)

然后你可以以Retrofit不同的方式绑定每个:

@Provides @Picture Retrofit providePictureRetrofit(…) {…}
@Provides @Weather Retrofit provideWeatherRetrofit(…) {…}
Run Code Online (Sandbox Code Playgroud)

并在需要的地方注入每个:

@Inject @Picture Retrofit pictureRetrofit;
@Inject @Weather Retrofit weatherRetrofit;
// (But constructor injection is better than field injection!)
Run Code Online (Sandbox Code Playgroud)