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 thelogins()
method. - and in that method, you recall the
dataProcessController.getApiClient()
and do the second call with it. However, as you never redidapiClient = 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
How to Store Object in Sqlite Database
Android: How to Check How Much Memory Is Remaining
Setting Action Bar Title and Subtitle
How to Repeat Notification Daily on Specific Time in Android Through Background Service
How to Display a One Time Welcome Screen
What Would Happen If Android App Is Released with Debuggable On
Android Understanding Heap Sizes
How to Get The Dimensions of a Drawable in an Imageview
Android 4.4.2 - Java.Lang.Runtimeexception: Performing Stop of Activity That Is Not Resumed
How to Place App Icon on Launcher Home Screen
Set Starting Height of Collapsingtoolbarlayout
Exception When Opening Parse Push Notification
Disable Icon Colorstatelist in Navigationview
Bitmapdrawable Deprecated Alternative
Android Viewpager Padding/Margin Between Page Fragments