前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Retrofit 动态管理和修改 BaseUrl,从未如此简单

Retrofit 动态管理和修改 BaseUrl,从未如此简单

原创
作者头像
CCCruch
修改2019-09-16 18:16:29
5.2K0
修改2019-09-16 18:16:29
举报
文章被收录于专栏:安卓开发干货分享

需求场景

在使用retrfoit做网络请求开发的时候,如果app涉及到多个不同 BaseUrl,仅仅是baseUrl不同,retrofit的其他配置都是一样的,我们不得不创建管理多个retrofit实例,或者需要在Service接口处修改@Get @Url等传入完整的url地址。这其实不是我们所期望的,因为如果有很多不同baseurl 地址的请求,我们可能某个baseurl只有一个或者很少的service使用的到,亦或者很多接口需要频繁的调用。我们不期望管理多个retrofit实例,是否可以只创建一个retrofit对象就能解决全部问题呢?答案肯定是可以的。

一帮的解决方案

  • 配置多个retrofit对象
  • okhttp拦截器Interceptorintercept(Chain chain)方法里做拦截

具体实现的话网上很多,这里不多做介绍

基于okhttps.Call.Factory的解决方案

研究retrofit的源代码我们知道,retrofit最终发起请求是从OkHttpCall里面,createRawCall 方法创建最终的okhttp3.Call对象,下面是代码

代码语言:txt
复制
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方法里面做文章呢。

callFactory是从哪里来的呢?可以看一下Retrofit这个类的代码可以知道,是通过client和callFactory

这两个方法赋值的,那怎么才能拦截上面的newCall方法,当然是自定义CallFactory了。

代码语言:txt
复制
/**
 * 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

难道我们要全部重写OkHttpClient里面的方法?这里当然不需要,我们只需要代理一下newCall方法就OK了,核心代码如下

代码语言:txt
复制
/**
 * 创建时间: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静态或者动态的方式都可以替换

代码语言:txt
复制
@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的处理比较简单,开发者可以自己实现和管理,这个方法是开放的。

是不是绿色、环保、无污染,代码侵入性极低。

源码地址:

https://github.com/xchengDroid/retrofit-helper

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 需求场景
    • 一帮的解决方案
      • 基于okhttps.Call.Factory的解决方案
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档