Dagger + Update Dynamic URL

PROBLEM

I need to call the API from the domains entered by USER, and I need to change my single Retrofit before the call corresponding to the entered data.

Is there a way to "reset" my singleton to make it recreate?

or

Is there a way to update my baseUrl my data (possibly in an Interceptor?) baseUrl before the call?

CODE

Loner

 @Provides @Singleton Retrofit provideRetrofit(SharedPreferences prefs) { String apiUrl = "https://%1s%2s"; apiUrl = String.format(apiUrl, prefs.getString(ACCOUNT_SUBDOMAIN, null), prefs.getString(ACCOUNT_DOMAIN, null)); OkHttpClient httpClient = new OkHttpClient.Builder() .addInterceptor(new HeaderInterceptor()) .build(); return new Retrofit.Builder() .baseUrl(apiUrl) .addConverterFactory(GsonConverterFactory.create()) .client(httpClient) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); } @Provides @Singleton API provideAPI(Retrofit retrofit) { return retrofit.create(API.class); } 

API

 @FormUrlEncoded @POST("endpoint") Observable<Response> logIn(@Field("login") String login, @Field("password") String password); 

How does it work now

Well, the idea was to save user domain data through SharedPrefs before calling the API and change baseUrl with a formatted string.

+7
android retrofit retrofit2 dagger dagger-2
source share
2 answers

Here I see 2 options:

  • Use the dagger as intended. For each baseUrl your own Retrofit client or
  • Use the interceptor to modify the request before sending it.

Dagger approach

If you were to use brute force URLs, that would probably not be the right choice, as it relies on creating a new Retrofit instance for each.

Now every time the URL changes, you simply recreate the next UrlComponent demonstrated by providing it with a new UrlModule .

Cleaning

Clear the @Singleton module @Singleton that it provides GsonConverterFactory and RxJavaCallAdapterFactory to properly use the dagger and not recreate common objects.

 @Module public class SingletonModule { @Provides @Singleton GsonConverterFactory provideOkHttpClient() {/**/} @Provides @Singleton RxJavaCallAdapterFactory provideOkHttpClient() {/**/} } @Singleton @Component(modules = SingletonModule.class) interface SingletonComponent { // sub component UrlComponent plus(UrlModule component); } 

URL scope

Enter @UrlScope to span your Retrofit instances.

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

Then create a subcomponent

 @SubComponent(modules=UrlModule.class) public interface UrlComponent {} 

And a module for him

 @Module class UrlModule { private final String mUrl; UrlModule(String url) { mUrl = url; } @Provides String provideUrl() { return mUrl; } @Provides @UrlScope OkHttpClient provideOkHttpClient(String url) { return new OkHttpClient.Builder().build(); } @Provides @UrlScope Retrofit provideRetrofit(OkHttpClient client) { return new Retrofit.Builder().build(); } } 

Use Retrofit Scope

Create an instance of the component and use it.

 class Dagger { public void demo() { UrlModule module = new UrlModule(/*some url*/); SingletonComponent singletonComponent = DaggerSingletonComponent.create(); UrlComponent urlComponent = singletonComponent.plus(module); urlComponent.getRetrofit(); // done. } } 

OkHttp Approach

Provide the interceptor properly ( @Singleton in this case) and implement the appropriate logic.

 @Module class SingletonModule { @Provides @Singleton GsonConverterFactory provideGsonConverter() { /**/ } @Provides @Singleton RxJavaCallAdapterFactory provideRxJavaCallAdapter() { /**/ } @Provides @Singleton MyApiInterceptor provideMyApiInterceptor() { /**/ } @Provides @Singleton OkHttpClient provideOkHttpClient(MyApiInterceptor interceptor) { return new OkHttpClient.Builder().build(); } @Provides @Singleton Retrofit provideRetrofit(OkHttpClient client) { return new Retrofit.Builder().build(); } } @Singleton @Component(modules = SingletonModule.class) interface SingletonComponent { Retrofit getRetrofit(); MyApiInterceptor getInterceptor(); } 

todo MyApiInterceptor . You will need to set the setter for the base url and then just rewrite / modify the requests going through.

Then try using it again.

 class Dagger { public void demo() { SingletonComponent singletonComponent = DaggerSingletonComponent.create(); MyService service = singletonComponent.getRetrofit().create(MyService.class); MyApiInterceptor interceptor = singletonComponent.getInterceptor(); interceptor.setBaseUrl(myUrlA); service.doA(); interceptor.setBaseUrl(someOtherUrl); service.doB(); } } 

As a third approach, you can also use reflection to directly change the base URL: I added this last for completeness only.

+9
source share

You can implement BaseUrl and pass this instead of a fixed URL. check this link Another approach implements Endpoint and uses setUrl() . Therefore, to change some header value at runtime, you can use an interceptor and add it to OkHttp.

+5
source share

All Articles