在使用retrfoit作网络请求开发的时候,若是app涉及到多个不一样 BaseUrl,仅仅是baseUrl不一样,retrofit的其余配置都是同样的,咱们不得不建立管理多个retrofit实例,或者须要在Service接口处修改@Get @Url等传入完整的url地址。这其实不是咱们所指望的,由于若是有不少不一样baseurl 地址的请求,咱们可能某个baseurl只有一个或者不多的service使用的到,亦或者不少接口须要频繁的调用。咱们不指望管理多个retrofit实例,是否能够只建立一个retrofit对象就能解决所有问题呢?答案确定是能够的。java
配置多个retrofit对象android
okhttp拦截器Interceptor
的 intercept(Chain chain)
方法里作拦截git
具体实现的话网上不少,这里很少作介绍github
okhttps.Call.Factory
的解决方案研究retrofit的源代码咱们知道,retrofit最终发起请求是从OkHttpCall
里面,createRawCall
方法建立最终的okhttp3.Call
对象,下面是代码网络
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
复制代码
咱们能够看到是经过callFactory对象建立的,那咱们能不能从newCall方法里面作文章呢。app
callFactory
是从哪里来的呢?能够看一下Retrofit
这个类的代码能够知道,是经过client和callFactoryide
这两个方法赋值的,那怎么才能拦截上面的newCall
方法,固然是自定义CallFactory
了。ui
/** * The HTTP client used for requests. * <p> * This is a convenience method for calling {@link #callFactory}. */
public Builder client(OkHttpClient client) {
return callFactory(checkNotNull(client, "client == null"));
}
/** * Specify a custom call factory for creating {@link Call} instances. * <p> * Note: Calling {@link #client} automatically sets this value. */
public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = checkNotNull(factory, "factory == null");
return this;
}
复制代码
自定义CallFactory
this
难道咱们要所有重写OkHttpClient里面的方法?这里固然不须要,咱们只须要代理一下newCall方法就OK了,核心代码以下url
/** * 建立时间:2019-09-04 * 编写人:chengxin * 功能描述:代理{@link okhttp3.Call.Factory} 拦截{@link #newCall(Request)}方法 */
public abstract class CallFactoryProxy implements Call.Factory {
private static final String NAME_BASE_URL = "BaseUrlName";
private final Call.Factory delegate;
public CallFactoryProxy(Call.Factory delegate) {
this.delegate = delegate;
}
@Override
public Call newCall(Request request) {
String baseUrlName = request.header(NAME_BASE_URL);
if (baseUrlName != null) {
HttpUrl newHttpUrl = getNewUrl(baseUrlName, request);
if (newHttpUrl != null) {
Request newRequest = request.newBuilder().url(newHttpUrl).build();
return delegate.newCall(newRequest);
} else {
Log.w(RetrofitFactory.TAG, "getNewUrl() return null when baseUrlName==" + baseUrlName);
}
}
return delegate.newCall(request);
}
@Nullable
protected abstract HttpUrl getNewUrl(String baseUrlName, Request request);
}
复制代码
这里能够看到 咱们抽象了 gewNewUrl
方法,只要继承CallFactoryProxy
,重写方法getNewUrl
方法,返回新的HttpUrl对象便可。那咱们怎么才能知道哪一个请求须要替换HttpUrl呢?经过@Headers或者@Header静态或者动态的方式均可以替换
@FormUrlEncoded
@Headers("BaseUrlName:baidu")//静态替换
@POST("user/login")
Call<LoginInfo> getLogin(@Field("username") String username, @Field("password") String password);
@FormUrlEncoded
@POST("user/login")
Call<LoginInfo> getLogin(@Header("BaseUrlName")/*动态替换*/ String baseUrlName, @Field("username") String username, @Field("password") String password);
构建Retrofit对象
OkHttpClient client = new OkHttpClient.Builder()
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://wanandroid.com/")
.callFactory(new CallFactoryProxy(client) {
@Nullable
@Override
protected HttpUrl getNewUrl(String baseUrlName, Request request) {
if (baseUrlName.equals("baidu")) {
String oldUrl = request.url().toString();
String newUrl = oldUrl.replace("https://wanandroid.com/", "https://www.baidu.com/");
return HttpUrl.get(newUrl);
}
return null;
}
})
.addConverterFactory(GsonConverterFactory.create())
.build();
复制代码
这里对getNewUrl
的处理比较简单,开发者能够本身实现和管理,这个方法是开放的。
是否是绿色、环保、无污染,代码侵入性极低。
源码地址: github.com/xchengDroid…