Установить динамические базовый URL-адрес, используя Ретрофит 2.0 и Кинжал 2
Я пытаюсь выполнить действие входа с помощью Retrofit 2.0 с помощью Dagger 2
Вот как я настраиваю зависимость Retrofit
@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient client) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson)
.client(client)
.baseUrl(application.getUrl())
.build();
return retrofit;
}
Вот интерфейс API.
interface LoginAPI {
@GET(relative_path)
Call<Boolean> logMe();
}
У меня есть три разных базовых URL, в которые могут входить пользователи. Поэтому я не могу установить статический url-адрес при настройке зависимости Retrofit. Я создал методы setUrl () и getUrl () в классе приложений. После входа в систему пользователя я устанавливаю url-адрес на приложение перед вызовом вызова API.
Я использую ленивую инъекцию для модифицируйте вот так
Lazy<Retrofit> retrofit
Таким образом, Кинжал вводит зависимость только тогда, когда я могу вызвать
retrofit.get()
Эта часть хорошо работает. Я получил url-адрес, настроенный на модернизацию зависимости. Однако проблема возникает, когда пользователь вводит неверный базовый url (скажем, mywifi.domain.com), понимает, что это не тот, и меняет его(скажем, чтобы mydata.domain.com поскольку Dagger уже создал зависимость для дооснащения,это не повторится.
Поэтому я должен снова открыть приложение и ввести правильный url-адрес.
Я читаю: разные посты для настройки динамического адреса на Ретрофит, используя Кинжал. В моем случае ничего хорошего не вышло. Я что-нибудь пропустил?
4 ответов:
HostSelectionInterceptorсделано swankjesseimport 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()); } }Или вы можете либо заменить ваш модифицированный экземпляр (и, возможно, сохранить экземпляр в
RetrofitHolder, в котором вы можете изменить сам экземпляр и предоставить держатель через Dagger)...public class RetrofitHolder { Retrofit retrofit; //getter, setter }Или повторно использовать текущий экземпляр Retrofit и взломать новый URL с помощью reflection, потому что к черту правила. Retrofit имеет параметр
baseUrl, который являетсяprivate final, поэтому вы можете получить к нему доступ только с отражением.Field field = Retrofit.class.getDeclaredField("baseUrl"); field.setAccessible(true); okhttp3.HttpUrl newHttpUrl = HttpUrl.parse(newUrl); field.set(retrofit, newHttpUrl);
Библиотека Retrofit2 поставляется с
@Urlаннотация. Вы можете переопределитьbaseUrlследующим образом:Интерфейс API:
public interface UserService { @GET public Call<ResponseBody> profilePicture(@Url String url); }И вызовите API следующим образом:
Retrofit retrofit = Retrofit.Builder() .baseUrl("https://your.api.url/"); .build(); UserService service = retrofit.create(UserService.class); service.profilePicture("https://s3.amazon.com/profile-picture/path");Для получения более подробной информации см. Эту ссылку: https://futurestud.io/tutorials/retrofit-2-how-to-use-dynamic-urls-for-requests
Спасибо @EpicPandaForce за помощь. Если кто-то сталкивается с IllegalArgumentException, это мой рабочий код.
public class HostSelectionInterceptor implements Interceptor { private volatile String host; public void setHost(String host) { this.host = HttpUrl.parse(host).host(); } @Override public okhttp3.Response intercept(Chain chain) throws IOException { Request request = chain.request(); String reqUrl = request.url().host(); String host = this.host; if (host != null) { HttpUrl newUrl = request.url().newBuilder() .host(host) .build(); request = request.newBuilder() .url(newUrl) .build(); } return chain.proceed(request); } }
Вы можете создать экземпляр нового объекта, используя метод provide Без области видимости.
@Provides LoginAPI provideAPI(Gson gson, OkHttpClient client, BaseUrlHolder baseUrlHolder) { Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson) .client(client) .baseUrl(baseUrlHolder.get()) .build(); return retrofit.create(LoginAPI.class); } @AppScope @Provides BaseUrlHolder provideBaseUrlHolder() { return BaseUrlHolder("https://www.default.com") }
public class BaseUrlHolder { public String baseUrl; public BaseUrlHolder(String baseUrl) { this.baseUrl = baseUrl; } public String getBaseUrl() { return baseUrl; } public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; } }Теперь вы можете изменить базовый url, получив baseUrlHolder из компонента
App.appComponent.getBaseUrlHolder().set("https://www.changed.com"); this.loginApi = App.appComponent.getLoginApi();
Comments