Dagger + Retrofit动态网址

时间:2016-04-21 12:39:22

标签: android retrofit dagger retrofit2 dagger-2

问题

我需要从USER输入的域调用API,我需要在调用之前编辑我的Retrofit单例,这与插入的数据有关。

有没有办法重置"我的单身人士,强迫它重新创造?

有没有办法在调用之前用我的数据(可能是Interceptor?)更新我的baseUrl

CODE

单身

@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 个答案:

答案 0 :(得分:10)

我在这里看到两个选项:

  • 按照预期使用匕首。为每个baseUrlRetrofit客户端或
  • 创建
  • 使用拦截器在发送请求之前修改请求

Dagger方法

如果您使用暴力网址,这可能不是正确的选择,因为它依赖于为每个网址创建一个新的Retrofit实例。

现在,每当网址发生变化时,您只需通过向其提供新的UrlComponent来重新创建以下所示的UrlModule

清理

清理您的@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);
}

Url Scoped

引入@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。您需要为基本网址设置 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 - 我为了完整性而添加了最后一个。

答案 1 :(得分:5)

您可以实施<nav class="navbar navbar-inverse"> <div class="container-fluid"> <div class="navbar-header"> <a class="navbar-brand" href="#">WebSiteName</a> </div> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Home</a> </li> <li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Page 1 <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Page 1-1</a> </li> <li><a href="#">Page 1-2</a> </li> <li><a href="#">Page 1-3</a> </li> </ul> </li> <li><a href="#">Page 2</a> </li> <li><a href="#"><span class="glyphicon glyphicon-user"></span> Sign Up</a> </li> <li><a href="#"><span class="glyphicon glyphicon-log-in"></span> Login</a> </li> </ul> </div> </nav>并传递该内容而不是固定网址。check out this link 其他方法是实现BaseUrl并使用Endpoint。因此,为了在运行时更改某些标头值,您可以使用拦截器并将其添加到OkHttp。