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

时间:2016-03-11 20:15:58

标签: android dependency-injection dagger-2

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

继承我目前的代码:

模块:

@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;
//    }
}

组件:

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

    void inject (MarsWeatherWidget marsWeatherWidget);

}

类扩展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;
    }
}

最后我实际注入了它:

@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

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

2 个答案:

答案 0 :(得分:15)

提供相同类型的不同版本

您可以使用@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();
}

自定义@Qualifier

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

@Qualifier
@Retention(RUNTIME)
public @interface Picture {}

您只需使用此代替@Named(String)

注入合格版本

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

MyPictureService provideService(@Named("picture") Retrofit retrofit) {
    // ...
}

答案 1 :(得分:4)

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

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

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

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

@Documented
@Qualifier
public @interface Picture {}

@Documented
@Qualifier
public @interface Weather {}

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

@Provides @Picture Retrofit providePictureRetrofit(…) {…}
@Provides @Weather Retrofit provideWeatherRetrofit(…) {…}

并将其注入您需要的地方:

@Inject @Picture Retrofit pictureRetrofit;
@Inject @Weather Retrofit weatherRetrofit;
// (But constructor injection is better than field injection!)