Установить динамические базовый 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-адрес.



Я читаю: разные посты для настройки динамического адреса на Ретрофит, используя Кинжал. В моем случае ничего хорошего не вышло. Я что-нибудь пропустил?

538   4  

4 ответов:

Поддержка этого варианта использования была удалена в Retrofit2. Вместо этого рекомендуется использовать перехватчик Ohttp.

HostSelectionInterceptor сделано 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());
  }
}

Или вы можете либо заменить ваш модифицированный экземпляр (и, возможно, сохранить экземпляр в 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

    Ничего не найдено.