Кинжал + Модернизированный динамический URL-адрес

ПРОБЛЕМА

Мне нужно вызвать API из доменов, введенных пользователем USER, и мне нужно отредактировать мой Retrofit перед вызовом, соответствующим вставленным данным.

Есть ли способ «перезагрузить» мой синглтон, заставив его воссоздать?

или

Есть ли способ обновить мой baseUrl моими данными (может быть, в Interceptor?) baseUrl перед вызовом?

КОД

Одиночки

 @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); 

Как это работает сейчас

Ну, идея заключалась в том, чтобы сохранить данные домена пользователя через SharedPrefs до вызова API и изменить baseUrl с форматированной строкой.

Здесь я вижу 2 варианта:

  • Используйте кинжал, как он предназначен. Создайте для каждого baseUrl собственный клиент baseUrl или
  • Используйте перехватчик для изменения запроса перед его отправкой

Кинжал

Если бы вы использовали URL-адреса грубой силы, это, вероятно, не было бы правильным выбором, поскольку он основывается на создании нового экземпляра Retrofit для каждого.

Теперь каждый раз, когда URL изменяется, вы просто воссоздаете следующий продемонстрированный UrlComponent , предоставив ему новый UrlModule .

Очистить

Очистите модуль @Singleton , чтобы он обеспечивал GsonConverterFactory и RxJavaCallAdapterFactory чтобы правильно использовать кинжал и не воссоздавать общие объекты.

 @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

Представьте @UrlScope для охвата ваших экземпляров Retrofit .

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

Затем создайте подкомпонент

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

И модуль для него

 @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(); } } 

Использовать модифицированную Retrofit

Создайте экземпляр компонента и используйте его.

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

Подход OkHttp

Предоставьте должным образом перехватчик ( @Singleton в этом случае) и реализуйте соответствующую логику.

 @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 . Вам нужно будет установить сеттер для базового url, а затем просто переписать / изменить запросы, проходящие через.

Затем, снова, просто продолжайте использовать его.

 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(); } } 

В качестве третьего подхода вы также можете использовать отражение, чтобы непосредственно изменить базовый URL-адрес: я добавил это последнее только для полноты.

Вы можете реализовать BaseUrl и передать это вместо фиксированного URL. Проверьте эту ссылку. Другой подход реализует setUrl() и использует setUrl() что для изменения некоторого значения заголовка во время выполнения вы можете использовать перехватчик и добавить его в OkHttp.

Intereting Posts
Java.lang.NoClassDefFoundError: android.support.v7.app.AppCompatDelegateImplV14 в Xamarin Android Как предоставить разрешение на использование adb без укорачивания устройств Проверка сетевого подключения с помощью BroadcastReceiver на Android Как использовать tabHost для Android Платформа Cordova добавить android получить ошибку в JAVA_HOME Изменение состояния меню панели действий в зависимости от фрагмента Объекты темы, а не сбор мусора после завершения Получите вчера дату от android OnInterceptTouchEvent никогда не получает action_move Офлайн-карта в Android с использованием файла .map Sugar ORM не сохраняет данные в базе данных Кнопки раскрывающегося меню / Spinner, как те, что указаны в дизайнерских спецификациях от Google Синглтоны против контекста приложения в Android? Как оживить текст (очень длинный текст) прокручивается автоматически по горизонтали Java.lang.ClassNotFoundException в моем приложении для Android, но я понятия не имею, почему