Dagger 2和Retrofit 2更改基本URL

时间:2017-07-26 17:40:40

标签: java android dependency-injection retrofit2 dagger-2

我的情况我需要更改url dynamicaly,但我不想创建2个改造客户端实例。我试图通过拦截器修改来更改基本URL,但改造stil使用旧值。我做错了什么?

App.java

public class App extends Application {
    private static AppComponent appComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        appComponent =
                DaggerAppComponent
                        .builder()
                        .appModule(new AppModule(this))
                        .build();

    }

    @NonNull
    public static App get(@NonNull Context context) {
        return (App) context.getApplicationContext();
    }

    public static AppComponent getAppComponent() {
        return appComponent;
    }
}

AppModule.java

@Module
public class AppModule {
    private Context context;

    public AppModule(Context context) {
        this.context = context;
    }

    @Provides
    @Singleton
    Context provideContext() {
        return context;
    }

}

NetModule.java

@Module
public class NetModule {

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

    @Provides
    @Singleton
    OkHttpClient provideOkhttpClient() {
        OkHttpClient.Builder client = new OkHttpClient.Builder();
        client.readTimeout(15, TimeUnit.SECONDS);
        client.connectTimeout(20, TimeUnit.SECONDS);
        return client.build();
    }

    @Provides
    @Singleton
    Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
        return new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl("first.url.com")
                .client(okHttpClient)
                .build();
    }
}

NetComponent.java

@Singleton
@Component(modules = NetModule.class)
public interface NetComponent {
    Retrofit getRetrofit();

    MainInterceptor getInterceptor();
}

MainInterceptor.class

public class MainInterceptor implements Interceptor {
    private static MainInterceptor sInterceptor;
    private String mScheme;
    private String mHost;

    public static MainInterceptor get() {
        if (sInterceptor == null) {
            sInterceptor = new MainInterceptor();
        }
        return sInterceptor;
}

    private MainInterceptor() {
    }

    public void setInterceptor(String url) {
        HttpUrl httpUrl = HttpUrl.parse(url);
        mScheme = httpUrl.scheme();
        mHost = httpUrl.host();
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();

        if (mScheme != null && mHost != null) {
            HttpUrl newUrl = original.url().newBuilder()
                    .scheme(mScheme)
                    .host(mHost)
                    .build();
            original = original.newBuilder()
                    .url(newUrl)
                    .build();
        }
        return chain.proceed(original);
    }
}

这是在某个类中初始化组件的代码。

NetComponent component= DaggerNetComponent.create();
DataService service = component.getRetrofit().create(DataService.class);
MainInterceptor interceptor = component.getInterceptor();
interceptor.setInterceptor("second.url.com");
service.getSomeData()

之后,网址仍为“first.url.com”

4 个答案:

答案 0 :(得分:2)

简单的方法是使用@Named

@Provides
@Singleton
@Named("retrofit_1")
Retrofit provideRetrofit1(Gson gson, OkHttpClient okHttpClient) {
        return new Retrofit.Builder()
                ...
                .baseUrl("url_1.com")
                ...;}

@Provides
@Singleton
@Named("retrofit_2")
Retrofit provideRetrofit2(Gson gson, OkHttpClient okHttpClient) {
        return new Retrofit.Builder()
                ...
                .baseUrl("url_2.com")
                ...;}

然后使用相同的@Named:

@Provides
IApi1 provideApi_1(@Named("retrofit_1") RestAdapter adapter){....}

@Provides
IApi2 provideApi_2(@Named("retrofit_2") RestAdapter adapter){....}

答案 1 :(得分:1)

当您提供Retrofit时,您已经设置了baseUrl" first.url.com"

return new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .baseUrl("first.url.com")
            .client(okHttpClient) //<------ It not OkHttp with your MainInterCeptor
            .build();

有趣的事实是,使用新网址设置的MainInterceptor与您的Retrofit无关,因为Retrofit是使用OkHttp构建的

@Provides
@Singleton
OkHttpClient provideOkhttpClient() {
    OkHttpClient.Builder client = new OkHttpClient.Builder();
    client.readTimeout(15, TimeUnit.SECONDS);
    client.connectTimeout(20, TimeUnit.SECONDS);
    return client.build();
}

如果您想动态更改BASE_URL,有很多方法可以做到这一点。

public class ApiConstant {

    public static String BASE_URL = "yourUrl";

    private ApiConstant() {
    }
}

创建一个@Scope for Retrofit,因为它可以更改

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

然后在构建Retrofit时使用它

@Provides
@PerActivity
Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
    return new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .baseUrl("first.url.com")
            .client(ApiConstant.BASE_URL)
            .build();
}

然后在初始化BASE_URL时更改DaggerActivityComponent。 (或者为新网址创建一个新的@Scope)

阅读this documentation了解更多详情

希望这有帮助!

答案 2 :(得分:1)

在您的AppModule中添加拦截器

@Provides
@Singleton
OkHttpClient provideOkHttpClient(Cache cache, MainInterceptor interceptor) {
    OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .addInterceptor(interceptor)
            .cache(cache)
            .build();
    return okHttpClient;
}

然后在您的活动或演示者中设置URL,然后再调用改造服务

mInterceptor.setInterceptor(urlname);
mRetrofitService.call();

答案 3 :(得分:0)

如果您已经设置了基本URL,但只想对一个API调用而不是对所有API覆盖它,则可以轻松完成。

@PUT("https://my-api.com/user")
fun cancelOrder(@Path("user") user: String): Single<MyResponse>

同样适用于POST和GET。