Retrofit是square公司对网络请求okhttp的二次封装,通过注解反射的方式,配置网络请求的参数,支持多种返回数据格式解析,支持同步异步调用。
这是一份很详细的 Retrofit 2.0 使用教程里面很详细的讲了注解,数据解析器,网络请求适配。基础的知识都很容易,标记一些比较容易忽视的内容
@FormUrlEncoded
每个键值对需要用@Filed来注解键名,随后的对象需要提供值。否则会报错
@Multipart
表示发送form-encoded的数据(适用于 有文件 上传的场景)
@Multipart
@POST("mobile/upload")
Call<ResponseBody> upload(@Part MultipartBody.Part file);
------------------------------------------------------------------------------------------------------
// 创建 RequestBody,用于封装 请求RequestBody
RequestBody requestFile =
RequestBody.create(MediaType.parse("image/jpg"), file);
// image/jpg是我们要上传的文件类型,你总得告诉别人你传的文件是什么格式的对吧,对应了请求体中的Content-Type: image/jpeg
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
MultipartBody.Part.createFormData("file", file.getName(), requestFile);
-----------------------------------------------------------------------------------------------------
// 添加描述 Http是只能进行纯文本传输,所以在后来支持文件上传后,新增了一个MIME类型,叫multipart/form-data。
//上传文件时 Content-Type:multipart/form-data;同时有boundary分隔上传的内容
String descriptionString = "hello, 这是文件描述";
RequestBody description =
RequestBody.create(
MediaType.parse("multipart/form-data"), descriptionString);
-----------------------------------------------------------------------------------------------------
@Headers
Retrofit提供了两种方式来定义HTTP请求头:静态和动态。
静态通过添加注解的方式
public interface WeatherService {
@Headers("apikey:b86c2269fe6588bbe3b41924bb2f2da2")
@GET
Call<WeatherWrapper> weather(@Url String url, @Query("cityname") String cityName);
}
或者动态添加方法参数的方式
@GET
Call<WeatherWrapper> weather(@HeaderMap Map<String, String> headers, @Url String url, @Query("cityname") String cityName);
添加拦截器
在OkHttp中Interceptors拦截器是一种强大的机制,可以监视,重写和重试Call请求
20170529175638399.png
拦截器分为应用拦截器和网络拦截器
添加日志拦截器
class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request1 = chain.request();
long t1 = System.nanoTime();
Log.d("tag",String.format("Sending request %s on %s%n%s",
request1.url(), chain.connection(), request1.headers()));
Response response = chain.proceed(request1);
long t2 = System.nanoTime();
Log.d("tag",String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
return response;
}
}
//同时通过配置okhttpclient添加网络拦截器
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS)//设置超时时间
.addNetworkInterceptor(new LoggingInterceptor())
.retryOnConnectionFailure(true);
OkHttpClient client=builder.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Config.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
mApiService = retrofit.create(ApiService.class);
测试得到结果
2018-11-05_160239.png
同样 可以通过添加拦截器来添加请求头
okHttpClientBuilder.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("platform", "platform")//平台
.header("sysVersion", "sysVersion")//系统版本号
.header("device", "device")//设备信息
.header("screen", "screen")//屏幕大小
.header("uuid", "uuid")//设备唯一码
.header("version", "version")//app版本
.header("apiVersion", "apiVersion")//api版本
.header("token", "token")//令牌
.header("channelId", "channelId")//渠道
.header("networkType", "networkType");//网络类型
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
还有通过添加缓存拦截器来实现无缓存功能
public class CacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!NetUtil.isNetworkConnected()) {//没网强制从缓存读取(必须得写,不然断网状态下,退出应用,或者等待一分钟后,就获取不到缓存)
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (NetUtil.isNetworkConnected()) {//有网情况下,从服务器获取
int maxAge = BuildConfig.DEFAULT_COOKIE_NETWORK_TIME;
// 有网络时, 缓存最大保存时长为60s
response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader("Pragma")
.build();
} else {//没网情况下,一律从缓存获取
// 无网络时,设置超时为30天
int maxStale = BuildConfig.DEFAULT_COOKIE_NO_NETWORK_TIME;
response.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
return response;
}
CallAdapter
我们知道通过添加RxJavaCallAdapter可以将call类型编程observer类型。那么如何去变成其他类型呢?在Architecture Components的代码中就有例子,将call类型装换成livedata<ApiResponse>的示例,ApiResponse是一个判断网络请求是否成功的类
public class LiveDataCallAdapter<R> implements CallAdapter<R,LiveData<ApiResponse<R>>> {
private final Type responseType;
public LiveDataCallAdapter(Type responseType) {
this.responseType = responseType;
}
@Override
public Type responseType() {
return responseType;
}
@Override
public LiveData<ApiResponse<R>> adapt(final Call<R> call) {
return new LiveData<ApiResponse<R>>() {
private AtomicBoolean started = new AtomicBoolean(false);//boolean的原子类型
@Override
protected void onActive() {
super.onActive();
if (started.compareAndSet(false,true)){ //compareAndSet预期arg0跟started是否一致,一致则started赋值为arg1;返回值实际上是是否成功修改
call.enqueue(new Callback<R>() {
@Override
public void onResponse(Call<R> call, Response<R> response) {
postValue(new ApiResponse<>(response));
}
@Override
public void onFailure(Call<R> call, Throwable t) {
postValue(new ApiResponse<R>(t));
}
});
}
}
};
}
}
---------------------------------------------------------------------------------------------------------
public class LiveDataCallAdapterFactory extends CallAdapter.Factory {
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != LiveData.class) {
return null;
}
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
if (rawObservableType != ApiResponse.class) {
throw new IllegalArgumentException("type must be a resource");
}
if (! (observableType instanceof ParameterizedType)) {
throw new IllegalArgumentException("resource must be parameterized");
}
Type bodyType = getParameterUpperBound(0, (ParameterizedType) observableType);
return new LiveDataCallAdapter<>(bodyType);
}
}
网友评论