Retrofit动态更换baseUrl
2019-12-03 本文已影响0人
竖起大拇指
1.一般一个应用都只创建一个Retrofit实例,但是当碰到需要的网络请求的baseUrl不止一个的时候,就要考虑如何给retrofit对象根据不同的请求接口更换不同的baseUrl了。
2.实现方法如下
companion object{
private const val DEFAULT_TIME:Long=30*1000
private var okHttpClient=OkHttpClient.Builder().connectTimeout(DEFAULT_TIME,TimeUnit.MILLISECONDS)
.writeTimeout(DEFAULT_TIME,TimeUnit.MILLISECONDS).readTimeout(DEFAULT_TIME,TimeUnit.MILLISECONDS).addInterceptor(
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC)
).addInterceptor(ChangeBaseUrlInterceptor())
.retryOnConnectionFailure(true).build()
private var retrofit: Retrofit = Retrofit.Builder().client(okHttpClient)
.baseUrl(Constants.BaseUrl) //设置网络请求的Url地址
.addConverterFactory(GsonConverterFactory.create()) //设置数据解析器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
@JvmStatic
fun isNetworkAvailable(): Boolean {
val connectivity = AbsApplication.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (connectivity == null) {
return false
} else {
val info = connectivity.allNetworkInfo
if (info != null) {
for (i in info.indices) {
if (info[i].state == NetworkInfo.State.CONNECTED) {
return true
}
}
}
}
return false
}
@JvmStatic
fun isNetworkOnWifi(): Boolean {
val connectivity =
AbsApplication.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (connectivity != null) {
val info = connectivity.allNetworkInfo
if (info != null) {
for (i in info.indices) {
if (info[i].typeName == "WIFI" && info[i].isConnected) {
return true
}
}
}
}
return false
}
fun <T> getApiService(reqService: Class<T>): T {
return retrofit!!.create(reqService)
}
}
3.API Server 接口定义如下
interface ApiService {
@Headers("domin:login")
@GET("values/5")
fun getRetrofit(): Call<BaseResponse<DemoBean>>
@Headers("domin:loginother")
@GET("values/5")
fun getRetrofitObserver(): Observable<BaseResponse<DemoBean>>
@POST
@Headers("Content-Type:application/json;charset=utf-8")
fun getAnswerObserver(@Url url:String,@Body body: RequestBody): Observable<Answer>
@POST
@Headers("Content-Type:application/json;charset=utf-8")
fun messagePush(@Url url: String,@Body body:RequestBody):Observable<PushResult>
@GET("/session")
fun getSession():Observable<ResponseBody>
}
这几个接口的baseUrl都是不一样的,怎么区分呢,通过给接口添加注解,设置其请求头属性domin的值
下面看一下自定义拦截器是怎么根据请求头的domin属性更换为每个接口更换baseUrl的
object URLConstant{
const val BASE_URL = "https://login.weixin.qq.com"
const val BASE_LOGIN_URL = "https://wx.qq.com"
const val BASE_LOGIN_OTHER_URL = "https://wx2.qq.com"
const val LOGIN_OTHER = "loginother"
const val LOGIN = "login"
const val DOMAIN = "domain"
}
class ChangeBaseUrlInterceptor :Interceptor{
override fun intercept(chain: Interceptor.Chain): Response {
//获取request
var request=chain.request()
//从request中获取原有的HttpUrl实列 oldHttpUrl
var oldHttpUrl=request.url()
//获取request的创建者
var builder=request.newBuilder()
//从request中获取headers 通过给定的建的url_name
var headerValues=request.headers(URLConstant.DOMAIN)
if(headerValues!=null&&headerValues.size>0) {
builder.removeHeader(URLConstant.DOMAIN)
var headValue = headerValues[0]
var newBaseUrl: HttpUrl?
newBaseUrl = when (headValue) {
URLConstant.LOGIN -> {
HttpUrl.parse(URLConstant.BASE_LOGIN_URL)
}
URLConstant.LOGIN_OTHER -> {
HttpUrl.parse(URLConstant.BASE_LOGIN_OTHER_URL)
}
else -> {
HttpUrl.parse(URLConstant.BASE_URL)
}
}
newBaseUrl?.run {
var newHttpUrl =
oldHttpUrl.newBuilder().scheme(scheme()).host(host())
.port(port()).build()
return chain.proceed(builder.url(newHttpUrl).build())
}
}
return chain.proceed(request)
}
}
这是一个自定义的网络请求拦截器,在创建Retrofit对象的时候已经把拦截器设置给了Retrofit,那么网络请求就会分发到这个拦截器,这个拦截器接收到网络请求之后,就会根据需求对网络请求做一些处理,然后再通过请求链把这个网络请求再向下一个拦截器分发。这个过程使用了责任链的设计模式,就是当一个任务下达之后,从上一级交由下一级处理,上一级可以根据实际情况是拦截任务自己处理还是继续分发给下一级,这个任务最终会被某一级处理掉或者都无法处理被抛弃掉,这个就和Android的view事件分发机制的原理是一样的。
Http请求采用这种责任链模式的好处是网络请求可以分层处理,每一层只实现某一特定功能即可,这样对整个过程进行了解耦,易于理解。Retrofit请求更换baseUrl就是这样实现的