背景:Android开发时,需要两个平台切换,项目中网络请求是用的Retrofit这块,发现没有直接切换的接口,百度一下,大部分直接是通过拦截器里面进行切换,说Retrofit中baseUrl是final类型,不能反射修改。通过测试后发现final值是可以修改的(包括基本类型),但是final值的初始化要在构造方法中赋值。
解决思路:
+. 直接替换掉Retrofit中的baseUrl
public final class Retrofit { private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>(); final okhttp3.Call.Factory callFactory; final HttpUrl baseUrl; final List<Converter.Factory> converterFactories; final List<CallAdapter.Factory> callAdapterFactories; final @Nullable Executor callbackExecutor; final boolean validateEagerly;
反射替换代码如下:
//baseUrl:切换的url //retrofit:对于的Retrofit实例 HttpUrl httpUrl = HttpUrl.parse(baseUrl); Field field = retrofit.getClass().getDeclaredField("baseUrl"); field.setAccessible(true); field.set(retrofit, httpUrl);
单点可以跟踪查看,retrofit中的baseUrl确实已经替换成功,但是去请求数据时,发现还是之前的数据。
具体原因跟踪源码:
ServiceMethod<?, ?> loadServiceMethod(Method method) { ServiceMethod<?, ?> result = serviceMethodCache.get(method); if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder<>(this, method).build(); serviceMethodCache.put(method, result); } } return result; }
Retrofit会根据Method缓存请求,如果之前请求过,就是你切换了baseUrl,请求同个Method,那还是之前的,对于这样,把对应的缓存清理下就行。
field = retrofit.getClass().getDeclaredField("serviceMethodCache"); field.setAccessible(true); Map serviceMethodCache = (Map) field.get(retrofit); serviceMethodCache.clear();
再测试下,可以成功切换。
完整代码如下:
public static void baseUrl(Retrofit retrofit, String baseUrl) throws Exception { HttpUrl httpUrl = HttpUrl.parse(baseUrl); Field field = retrofit.getClass().getDeclaredField("baseUrl"); field.setAccessible(true); field.set(retrofit, httpUrl); field = retrofit.getClass().getDeclaredField("serviceMethodCache"); field.setAccessible(true); Map serviceMethodCache = (Map) field.get(retrofit); serviceMethodCache.clear(); }
当网络请求正在进行时,这种暴力切换方式,可能会有些意想不到的问题,至于其它问题,后续发现追加。
相关推荐
以最简洁的 Api 让 Retrofit 同时支持多个 BaseUrl 以及动态改变 BaseUrl
retrofit-helper Retrofit是很多android开发者都在使用的Http请求库!他负责网络请求接口的封装,底层...动态替换retrofit 的baseUrl CallFactoryProxy 采用代理的方式灵活简单 绑定Activity或者Fragment生命周期 LifeCa
主要给大家介绍了关于如何动态改变Retrofit的base url和rest版本的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
retrofit学习、retrofit rxjava封装、retrofit mvp rxjava
Retrofit 2 Synchronous Adapter A synchronous CallAdapter.Factory implementation for Retrofit 2. This project brings Retrofit 1's synchronous usage to Retrofit 2. Usage // Setup retrofit Retrofit ...
Retrofit2 使用Demo
retrofit下载apk文件,retrofit下载apk文件retrofit下载apk文件retrofit下载apk文件retrofit下载apk文件retrofit下载apk文件retrofit下载apk文件retrofit下载apk文件retrofit下载apk文件retrofit下载apk文件retrofit...
个人写的一个mvp+retrofit2.0 的简单登录demo。希望对刚学习mvp和retrofit的童鞋有帮助。
var service = retrofitFor< MessagingService> { // this: Retrofit.Builder baseUrl(server.url( " " )) addConverterFactory( GsonConverterFactory .create()) } service.getMessage().enqueue { always { // ...
Retrofit的简单分装类,将call中的泛型改为需要的实体类然后加入接口就可以直接使用 gradle中需要添加 implementation 'com.squareup.retrofit2:converter-gson:2.0.2' implementation '...
retrofit封装retrofit封装retrofit封装retrofit封装retrofit封装retrofit封装retrofit封装retrofit封装retrofit封装
Let Retrofit support multiple baseUrl and can be change the baseUrl at runtime. 中文说明 Overview Notice Framework analysis 1 Framework analysis 2 More complete sample Download implementation 'me....
Retrofit大文件下载进度监听, , , , ,
RxJava+Retrofit+MVP的简单Demo,有错误请留言指出
RxJava整合Retrofit2.0网络框架,将城市天气查询作为一个使用案例
MVP+retrofit+rxjva简单模板
里面介绍了retrofit的使用,样式很多欢迎下载。可以运用到项目中
利用泛型和单例封装Retrofit网络访问
Android实战——Retrofit2的使用和封装
Retrofit2+OkHttp3+RxJava的网络框架