Dagger +加装动态网址 [英] Dagger + Retrofit dynamic URL

查看:103
本文介绍了Dagger +加装动态网址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题

我需要从USER输入的域中调用API,并且需要在调用之前根据插入的数据编辑Retrofit单例.

是否有办法重置"我的单身人士,迫使其重新创建?

有没有一种方法可以在通话前用我的数据(也许在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);

现在如何工作

好主意是在API调用之前通过SharedPrefs保存用户域数据,并使用格式化的String修改baseUrl.

解决方案

我在这里看到2个选项:

  • 按预期使用匕首.为每个baseUrl自己的Retrofit客户端创建,或
  • 在发送请求之前使用拦截器修改请求

匕首方法

如果要强行使用URL,这可能不是正确的选择,因为它依赖于为每个URL创建一个新的Retrofit实例.

现在,每次更改URL时,您只需为其提供新的UrlModule来重新创建以下演示的UrlComponent.

清理

清理您的@Singleton模块,以便它提供GsonConverterFactoryRxJavaCallAdapterFactory以正确使用匕首而不重新创建共享对象.

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

范围内的网址

引入一个@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();
}

待办事项 实施MyApiInterceptor.您需要为基本网址设置一个 setter ,然后重写/修改通过的请求.

然后再次使用它.

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


作为第三种方法,您还可以使用 reflection 直接更改基础URL的基础.

PROBLEM

I need to call API from domains entered by USER and I need to edit my Retrofit singleton before the call accordingly to the inserted data.

Is there a way to "reset" my singleton, forcing it to recreate?

or

Is there a way to update my baseUrl with my data (maybe in Interceptor?) just before call?

CODE

Singletons

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

How it works now

Well the idea was to save user domain data via SharedPrefs before API call and modify baseUrl with formatted String.

解决方案

I see 2 options here:

  • Use dagger as it is intended. Create for every baseUrl their own Retrofit client, or
  • Use an interceptor to modify the request before sending it

Dagger approach

If you were to brute force urls, this would probably not be the right choice, since it relies on creating a new Retrofit instance for each.

Now every time the url changes, you just recreate the following demonstrated UrlComponent by supplying it with a new UrlModule.

Clean up

Clean your @Singleton module, so that it provides GsonConverterFactory, and RxJavaCallAdapterFactory to make proper use of dagger and not recreate shared objects.

@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 Scoped

Introduce a @UrlScope to scope your Retrofit instances.

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

Then create a subcomponent

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

And a module for it

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

}

Use scoped Retrofit

Instantiate the component and use it.

class Dagger {

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

        urlComponent.getRetrofit(); // done.
    }
}


OkHttp approach

Provide a properly scoped interceptor (@Singleton in this case) and implement the corresponding logic.

@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 Implement the MyApiInterceptor. You will need to have a setter for the base url, and then just rewrite / modify the requests coming through.

Then, again, just go ahead and use it.

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


As a third approach, you could also use reflection to just directly change base the base URL—I added this last just for completeness.

这篇关于Dagger +加装动态网址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆