Retrofit - Change Baseurl

Set dynamic base url using Retrofit 2.0 and Dagger 2

Support for this use-case was removed in Retrofit2. The recommendation is to use an OkHttp interceptor instead.

HostSelectionInterceptor made by swankjesse

import java.io.IOException;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;

/** An interceptor that allows runtime changes to the URL hostname. */
public final class HostSelectionInterceptor implements Interceptor {
private volatile String host;

public void setHost(String host) {
this.host = host;
}

@Override public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String host = this.host;
if (host != null) {
//HttpUrl newUrl = request.url().newBuilder()
// .host(host)
// .build();
HttpUrl newUrl = HttpUrl.parse(host);
request = request.newBuilder()
.url(newUrl)
.build();
}
return chain.proceed(request);
}

public static void main(String[] args) throws Exception {
HostSelectionInterceptor interceptor = new HostSelectionInterceptor();

OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();

Request request = new Request.Builder()
.url("http://www.coca-cola.com/robots.txt")
.build();

okhttp3.Call call1 = okHttpClient.newCall(request);
okhttp3.Response response1 = call1.execute();
System.out.println("RESPONSE FROM: " + response1.request().url());
System.out.println(response1.body().string());

interceptor.setHost("www.pepsi.com");

okhttp3.Call call2 = okHttpClient.newCall(request);
okhttp3.Response response2 = call2.execute();
System.out.println("RESPONSE FROM: " + response2.request().url());
System.out.println(response2.body().string());
}
}

Or you can either replace your Retrofit instance (and possibly store the instance in a RetrofitHolder in which you can modify the instance itself, and provide the holder through Dagger)...

public class RetrofitHolder {
Retrofit retrofit;

//getter, setter
}

Or re-use your current Retrofit instance and hack the new URL in with reflection, because screw the rules. Retrofit has a baseUrl parameter which is private final, therefore you can access it only with reflection.

Field field = Retrofit.class.getDeclaredField("baseUrl");
field.setAccessible(true);
okhttp3.HttpUrl newHttpUrl = HttpUrl.parse(newUrl);
field.set(retrofit, newHttpUrl);

how to change baseURL in retrofit interface?

You can just create a different retrofit instance like this :

//Build retrofit instance
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl).build();

Then you instanciate your service.

    apiService = retrofit.create(ApiService.class);

How to Change API Base Url at Runtime(Retrofit,Android,Java)?

Base on your comments, I would say that you are correctly changing the API url on your builder, but that your second call still uses an instance of service where the url has not changed.

To explain a little more, from what I understand this is how everything gets executed:

  • when fragment is created, the apiClient is created and pointing to the first url
  • with dataProcessController.getApiClient() in your first call, you are getting the service that is pointing to the first url and then execute the call.
  • when the call is successful, you read the new url from result and update the ServiceGenerator with that new url. Then you execute the logins() method.
  • and in that method, you recall the dataProcessController.getApiClient() and do the second call with it. However, as you never redid apiClient = ServiceGenerator.createService(ApiClient.class);, the apiClient instance you are getting is still pointing to the first url, because it hasn't been notified that the url changed.

What I would try here, would be to change the method getApiClient() in your DataProcessController class to something like this:

public ApiClient getApiClient() {
apiClient = ServiceGenerator.createService(ApiClient.class);
return apiClient;
}

and see if this is work better.

Or if you don't want to regenerate the service inside that function, you can also do something like this:

public class DataProcessController { 
private ApiClient apiClient = null;

private DataProcessController() {
regenerateClient();
}

public ApiClient getApiClient() { return apiClient; }

// add this to regenerate the client whenever url changes
public void regenerateClient() {
apiClient = ServiceGenerator.createService(ApiClient.class);
}
}

then, everytime you do change the url, do this:

ServiceGenerator.changeApiBaseUrl(baseUrls);
dataProcessController.regenerateClient();

and you should get a client that points to the correct url everytime you do dataProcessController.getApiClient()

Dagger + Retrofit dynamic baseUrl

After you have created an instance of retrofit you cannot change the base url. However, for each single request method in your interface you can change them dynamically. You can create a new instance of retrofit for each request but I don't suggest it because it is not efficient.

@POST()
suspend fun createRoom(
@Url url: String = "www.....",
@Body body: BodyDTO
): Response

in your case, you probably forget to add http method type annotation to your request method.



Related Topics



Leave a reply



Submit