Retrofit运行时动态改变BaseUrl解决方案

哪个小可爱在偷偷的看我~~


偷瞄.gif
背景

Android正式项目中可能会涉及到多个BaseUrl,使用Retrofit开发者可能会遇到多BaseUrl不是很好处理情况,下面给大家介绍俩种Retrofit动态设置BaseUrl方法,以便大家不时之需

第一种方案

简单粗暴解决方案,利用Retrofit请求优先级,因为Retrofit支持全路径,比如

 @GET("http://www.baidu.com")
 Observable<Object> getApi(@Path("param") String param);
第二种方案

Retrofit默认只能设置一个BaseUrl,没有提供其Api去修改,所以我们只能通过其他方案去实现,网上也有很多介绍的,但尝试用了下感觉很不理想,于是自己稍加封装了下,思路其实简单。

思路:一个Retrofit只能设置一个BaseUrl,这样我们可以创建多个Retrofit不就可以了吗?但如果一个请求创建一个Retrofit必然是不理想的,所以我们可以有几个BaseUrl创建几个,有人会说这样不会造成内存的开销吗?答案是不会的,一个项目中也不会出现N多个BaseUrl,所以这点开销不用过于纠结

代码实现:在代码设计时可以尽可能去优化,所以当我们用到此BaseUrl时,再去创建,用不到不创建,这样便会出现个问题,怎样知道我应该使用哪个RetrofitRetrofit怎么去保存等问题,本人思路是创建成功便添加到集合缓存下载,使用的时候去比对集合中BaseUrl和当前是否匹配,如果一致从集合中获取,如果不一致去创建新的,如果使用没有传入BaseUrl便用默认的,最基本的判断,实现代码如下

1、正常创建Retrofit
public class ApiRetrofit {

    private static ApiRetrofit mApiRetrofit;
    private Retrofit retrofit;
    private ApiServer apiServer;
    public static String mBaseUrl = BaseContent.baseUrl;

    public ApiRetrofit() {
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        httpClientBuilder
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true);//错误重联
        retrofit = new Retrofit.Builder()
                .baseUrl(mBaseUrl )
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(httpClientBuilder.build())
                .build();

        apiServer = retrofit.create(ApiServer.class);
    }

    public static ApiRetrofit getInstance() {
        if (mApiRetrofit == null) {
            synchronized (Object.class) {
                if (mApiRetrofit == null) {
                    mApiRetrofit = new ApiRetrofit();
                }
            }
        }
        return mApiRetrofit;
    }
}
2、对创建Retrofit稍加封装,已适应我们的需求

新建保存对象的集合

private static List<Retrofit> mRetrofitList = new ArrayList<>();
private static List<ApiRetrofit> mApiRetrofitList = new ArrayList<>();

修改创建时候的逻辑,如果请求接口时传入BaseUrl,检测BaseUrl是否为空,如果为空使用默认接口,如果不为空,再从缓存的Retrofit中查找是否已经才创建过了,如果创建了用缓存的,如果没有创建则创建

注:这块可以用正则检查下传入的url是否为正规的域名,再做下判断

//创建Retrofit代码中加入
 apiServer = retrofit.create(ApiServer.class);
 mRetrofitList.add(retrofit);

public static ApiRetrofit getInstance() {
        mBaseUrl = BaseContent.baseUrl;

        int mIndex = -1;
        for (int i = 0; i < mRetrofitList.size(); i++) {
            if (BaseContent.baseUrl.equals(mRetrofitList.get(i).baseUrl().toString())) {
                mIndex = i;
                break;
            }
        }

        //新的baseUrl
        if (mIndex == -1) {
            synchronized (Object.class) {
                mApiRetrofit = new ApiRetrofit();
                mApiRetrofitList.add(mApiRetrofit);
                return mApiRetrofit;
            }
        } else {
            //以前已经创建过的baseUrl
            return mApiRetrofitList.get(mIndex);
        }
    }


    public static ApiRetrofit getInstance(String baseUrl) {
        if (!TextUtils.isEmpty(baseUrl)) {
            mBaseUrl = baseUrl;
        } else {
            mBaseUrl = BaseContent.baseUrl;
        }

        int mIndex = -1;
        for (int i = 0; i < mRetrofitList.size(); i++) {
            if (baseUrl.equals(mRetrofitList.get(i).baseUrl().toString())) {
                mIndex = i;
                break;
            }
        }

        //新的baseUrl
        if (mIndex == -1) {
            synchronized (Object.class) {
                mApiRetrofit = new ApiRetrofit();
                mApiRetrofitList.add(mApiRetrofit);
                return mApiRetrofit;
            }
        } else {
            //以前已经创建过的baseUrl
            return mApiRetrofitList.get(mIndex);
        }
    }
3、使用时写法

地址可以写成常量,不要我这样写,写成常量判断准确

ApiRetrofit.getInstance("http://www.baidu.com/").getApiService().getCeShi(params)


最后祝大家开发愉快!

推荐阅读更多精彩内容