1.Retrofit
Retrofit是基于okhttp封装的网络请求框架,网络请求的工作本质上是OkHttp完成,而Retrofit仅负责网络请求接口的封装。
OkHttp是安卓官方认证的网络请求框架,非常强大,但是它也有不少缺点:
①OkHttp配置网络请求是非常繁琐的,尤其是配置复杂网络请求body、请求头、参数的时候。
②数据解析过程需要用户手动拿到ResponseBody进行解析,难以复用。
③无法自动进行线程切换。
④如果存在嵌套网络请求,就会陷入“回调地狱”。
为了解决这些缺点,让网络请求在Android开发上易用,诞生了Retrofit框架,其实它本质上就是在OkHttp上套了层“壳子”,里面的请求还是基于OkHttp实现。
所以Retrofit封装OkHttp主要是以下几点:
①build模式创建网络请求基本配置
②用注解类组合HTTP网络请求
③提供Gson解析返回的json数据
④Executor完成线程切换
它请求实现的核心在于“注解”、“动态代理”、“反射”。
Retrofit用注解的形式组合HTTP请求,通过代理接口,处理请求的逻辑,最后执行请求。里面大量使用反射、工厂方法、抽象接口来实验低耦合和高扩展。
使用Retrofit,开发者不用关注网络通信的细节,只需要在接口文件中声明一系列方法和返回值,然后通过注解的方式指定该方法对应哪个服务器接口,以及需要提供哪些参数。当在程序中调用该方法时,Retrofit会自动向对应的服务器接口发起请求,并将响应的数据解析成返回值声明的类型。这样可以用更加面向对象的思维来进行网络操作。
2.Retrofit用法
①添加依赖
在项目build.gradle里面添加如下依赖:
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation("com.squareup.okhttp3:okhttp:4.9.1")
Retrofit是基于OkHttp二次封装的网络请求库, 所以这里要导入OkHttp的依赖。
gson是用来解析Json数据使用的。Retrofit也支持其他解析工具比如fastJson。
②创建Retrofit实例
Retrofit mRetrofit = new Retrofit.Builder()
.baseUrl(Config.baseUrl) //网络地址baseUrl不能为空,且强制要求必须以斜杠/结尾
.addConverterFactory( GsonConverterFactory.create())) //设置数据解析器工厂,使用Gson解析
.callbackExecutor( Executors.newSingleThreadExecutor()) //使用单独的线程处理 (这很重要,一般网络请求如果不设置可能不会报错,但是如果是下载文件就会报错)
.build();
③创建数据返回后的Bean类
将服务端返回的json数据格式化成需要用到的实体类:
public class LoginBean {
private int code;
private String msg;
public int getCode() { return code; }
public void setCode(int code) {
this.code = code;
}
public String getMsg() { return msg; }
public void setMsg(String msg) {
this.msg = msg;
}
}
④创建一个网络请求接口
public interface HttpList {
@FormUrlEncoded //该注解表示form表单,还有@Multipart表单可供使用,当然也可以不添加
@POST("test/login_test") //网络请求路径
Call<LoginBean> login(@Field("number") String number, @Field("password") String password); //@Field("number") 为post值的key
}
这是一个接口类,LoginBean则是数据返回后的Bean类,Retrofit会自动使用导入的Gson解析。
注意:@POST("test/login_test")路径最前面不能加斜杠/,否则它会自动裁剪路径,这样会导致路径错误。
⑥同步请求网络
private void postHttp2() {
HttpList httpList = mRetrofit.create( HttpList.class); //使用mRetrofit.create()创建网络请求接口代理,如果无改变Retrofit,也可以用一个单例类获取Retrofit
final Call<LoginBean> call = httpList.login("admin", "123456");
new Thread(new Runnable() { //Android主线程不能操作网络请求,所以new一个线程来操作
@Override
public void run() {
try {
Response<LoginBean> response = call.execute(); //同步请求网络
LoginBean bean = response.body();
Log.e(TAG, "onResponse: code=" + bean.getCode() + " message=" + bean.getMessage());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
首先用Retrofit.create()创建接口服务,拿到call对象之后调用execute同步方法,返回一个response对象,然后通过response获取从后端请求返回的数据,因为gson解析器做好了解析,这里只需要response.body().getCode()、response.body().getMsg());就能获取服务端返回的json数据里面key对应value值。
注意:因为是同步方法,不能直接在ui线程里面操作,不然会造成线程阻塞直接报出anr,所以在使用call同步方法时,要开启一个线程再去操作。
⑦异步请求
private void postHttp(){
HttpList httpList = mRetrofit.create( HttpList.class);
Call<LoginBean> call = httpList.login( "admin", "123456");
call.enqueue(new Callback<LoginBean>() {
@Override
public void onResponse(Call<LoginBean> call, Response<LoginBean> response) {
LoginBean bean = response.body();
Log.e(TAG, "onResponse: code=" + bean.getCode() + " message=" + bean.getMessage());
}
@Override
public void onFailure(Call<LoginBean> call, Throwable t) {
Log.e(TAG, "onFailure: 网络请求失败="+t.getMessage());
}
});
}
调用call里面enqueue异步方法,需要实现Callback接口里面的回调方法。因为是异步操作,所以不需要再另外开启线程来处理,框架已经处理好了。这样就完成了一个网络请求。
⑧取消网络请求
public void cancelHttp(){
HttpList httpList = mRetrofit.create( HttpList.class);
//这部分代码是告诉call是哪里来的,关键点就是这个call,当然也可以从回调里获取
mCall = httpList.login("admin", "123456");
mCall.cancel(); //取消请求
}
⑨添加Header头
1)以固定数据的形式添加头信息
public interface HttpList {
@Headers({"content1:one","content2:two"})
@POST("test/logout_test")
Call<LoginBean> logout();
}
2)以非固定数据的形式添加头信息
public interface HttpList {
@POST("test/logout_test")
Call<LoginBean> logout(@Header("content") String content);
}
⑩Body配置
Body一般有4个种类:
application/x-www-form-urlencoded 表单数据
multipart/form-data 表单文件上传
application/json 序列化JSON数据
text/xml XML数据
框架直接提供了2个Body:
public interface HttpList {
//application/x-www-form-urlencoded表单body
@FormUrlEncoded
@POST("test/login_test")
Call<LoginBean> login(@Field("number") String number, @Field("password") String password);
//multipart/form-data 此body支持文件上传与下载
@Multipart
@POST("test/login_test")
Call<LoginBean> login(@Field("number") String number, @Field("password") String password);
}
其他2个就需要自定义创建了,下面举例Json Body的创建:
public static RequestBody getRequestBody( String string) {
return RequestBody.create(MediaType.parse( "application/json; charset=utf-8"), string);
}
参数string直接导入需要发送给服务器的JSON的String值。
在接口类中参数需要设置为@Body RequestBody requestBody
@POST("app/system/demo")
Observable<UpdateInfo> demo(@Body RequestBody requestBody);
⑩添加配置的OkHttpClient(主要使用请求超时/拦截器等功能)
Retrofit是基于Okhttp开发的网络请求框架,所以它有一部分功能依然需要使用Okhttp的方式来配置,比如请求超时时间/设置拦截器等。
private void initHttpBase2() {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.retryOnConnectionFailure(false) //在连接失败时重试
.callTimeout(30, TimeUnit.SECONDS) //呼叫超时,设置此参数为整体流程请求的超时时间
.connectTimeout( 20,TimeUnit.SECONDS)//连接超时
.readTimeout(20,TimeUnit.SECONDS)//读取超时
.writeTimeout(20,TimeUnit.SECONDS)//写入超时
// .callTimeout()//呼叫超时,设置此参数为整体流程请求的超时时间
// .addInterceptor() //设置拦截器
// .authenticator() //设置认证器
// .proxy()//设置代理
.build();
mRetrofit = new Retrofit.Builder()
.client(okHttpClient)
……
.build();
}
3.源码分析
①retrofit.create()生成代理对象
以retrofit.create()为入口,它把网络请求配置的接口转换成一个实现了该接口的对象。里边核心的技术就是JDK动态代理。
Retrofit.java:
public <T> T create(final Class<T> service) {
validateServiceInterface(service); // 检查接口的合法性
// 动态代理,返回代理对象
return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() {
private final Platform platform = Platform.get(); // 获取平台信息,这里得到的是Android平台
private final Object[] emptyArgs = new Object[0]; // 定义空的参数数组
//每次调用接口中的方法都会走该方法,相当于就是接口方法的实现。参数proxy:代理对象,method:当前调用的接口方法,args:方法的参数
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) { // 如果是Object类中的方法则不做额外处理
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) { // 如果是Java8接口的默认实现方法,不做额外处理
return platform.invokeDefaultMethod( method, service, proxy, args);
}
// 重点,网络请求的具体实现、处理就在这里了
return loadServiceMethod(method) .invoke(args != null ? args : emptyArgs);
}
});
}
Retrofit通过JDK动态代理技术,将开发者创建的网络请求接口生成了一个实现该接口的代理对象。然后调用该接口中的方法时,就会执行InvocationHandler的invoke()方法,相当于是对原接口中方法的具体实现。
create()方法中最重要的就是最后一句:loadServiceMethod(method).invoke(args != null ? args : emptyArgs);这个过程会组织网络请求、解析响应结果、将响应结果返回。
这里分为loadServiceMethod()和invoke()两步。
②loadServiceMethod返回CallAdapted
loadServiceMethod()方法的主要任务就是解析网络请求接口方法上的注解信息,得到数据适配器、数据解析器对象,然后封装成一个CallAdapted返回。CallAdapted继承了ServiceMethod。
Retrofit.java:
ServiceMethod<?> loadServiceMethod(Method method) {
//先从缓存中找
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
// 缓存中没找到
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations( this, method); // 创建ServiceMethod对象
serviceMethodCache.put(method, result);//放入缓存
}
}
return result;
}
重点是parseAnnotations()方法:
ServiceMethod.java:
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); // 解析接口中调用的方法
return HttpServiceMethod.parseAnnotations( retrofit, method, requestFactory);
}
// 第二步要分析的invoke()方法就是这个
abstract @Nullable T invoke(Object[] args);
}
RequestFactory.parseAnnotations(retrofit, method)用于解析网络请求接口中对应方法上的注解信息、参数上的注解信息,准备网络请求的必要信息。
然后调用了HttpServiceMethod的parseAnnotations()。HttpServiceMethod类继承了ServiceMethod:
HttpServiceMethod.java:
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {
Annotation[] annotations = method.getAnnotations();
// 得到接口方法的返回值信息
adapterType = method.getGenericReturnType();
// 创建数据适配器对象。创建retrofit对象时设置了数据适配器工厂,数据适配器对象最终就是通过工厂创建的
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);
// 创建数据解析器对象,数据解析器对象最终就是通过数据解析器工厂创建的
Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter( retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);//返回一个CallAdapted对象
}
//重写ServiceMethod的invoke()方法
@Override final ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall< (requestFactory, args, callFactory, responseConverter); //创建一个OkHttpCall对象,OkHttpCall是个关键的类,网络请求的具体实现就在里边
return adapt(call, args); // adapt()是HttpServiceMethod中的一个抽象方法
}
protected abstract @Nullable ReturnT adapt( Call<ResponseT> call, Object[] args);
}
如果创建Retrofit对象时设置了RxJava数据适配器工厂、Gson数据解析器工厂,这里就会从工厂中得到对应的数据适配器和数据解析器,最后将它们封装到CallAdapted里。
CallAdapted是HttpServiceMethod的静态内部类,它继承了HttpServiceMethod,并实现了HttpServiceMethod的adapt()方法:
HttpServiceMethod.java:
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod< ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter; // callAdapter是刚刚得到的数据适配器
}
@Override protected ReturnT adapt( Call<ResponseT> call, Object[] args) {
// 调用数据适配器的adapt()方法,注意这里的参数call是OkHttpCall类型的
return callAdapter.adapt(call);
}
}
如果创建Retrofit的时候使用了RxJava的数据适配器,这里的adapt方法最终就会调用RxJava数据适配器的adapt()方法。
至此,loadServiceMethod()方法的执行流程就结束了,该方法最终返回了一个继承自HttpServiceMethod的CallAdapted对象。同时准备好了OkHttpCall、数据适配器以及数据解析器。
③数据适配器
调用ServiceMethod的invoke()方法最终就是调用RxJava数据适配器的adapt()方法,参数就是OkHttpCall。
数据适配器对象是通过数据适配器工厂RxJava2CallAdapterFactory创建的。
RxJava2CallAdapter的adapt()方法:
RxJava2CallAdapter.java:
@Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync ? new CallEnqueueObservable<>(call) : new CallExecuteObservable<>(call); // isAsync为false,call对象类型是OkHttpCall
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
// isBody为true,会执行这里
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
......
// 调用关联的hook函数。如果之前调用过RxJavaPlugins.setOnObservableAssembly()设置了一个observable,则会用设置的observable替换掉onAssembly()方法传入的observable。当然这里并不会,还是会返回上边创建的observable对象
return RxJavaPlugins.onAssembly( observable);
}
所以adapt()方法会返回一个Observable对象,但还是太过粗略了,需要进一步探究该对象的奥秘。
按照上边的分析,应该先执行new CallExecuteObservable<>(call),得到responseObservable对象,再执行new BodyObservable<>(responseObservable),对其进一步封装,所以先看CallExecuteObservable类是如何实现的:
final class CallExecuteObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
CallExecuteObservable(Call<T> originalCall) {
this.originalCall = originalCall;
}
// Observable订阅Observer时会执行该方法
@Override protected void subscribeActual( Observer<? super Response<T>> observer) {
Call<T> call = originalCall.clone();
// 将call对象封装成CallDisposable,以具有取消请求的功能
CallDisposable disposable = new CallDisposable(call);
// 产生了订阅关系
observer.onSubscribe(disposable);
if (disposable.isDisposed()) {
return;
}
boolean terminated = false;
try {
// call对象类型是OkHttpCall,execute()方法会执行OkHttp的同步网络请求
Response<T> response = call.execute();
if (!disposable.isDisposed()) {
// 将请求结果发送给observer
observer.onNext(response);
}
if (!disposable.isDisposed()) {
terminated = true;
// 通知observer,请求结果发送结束
observer.onComplete();
}
} catch (Throwable t) {
......
try {
// 通知observer,在网络请求、发送结果过程中出现了异常
observer.onError(t);
} catch (Throwable inner) {
......
}
}
}
}
private static final class CallDisposable implements Disposable {
private final Call<?> call;
private volatile boolean disposed;
CallDisposable(Call<?> call) {
this.call = call;
}
@Override public void dispose() {
disposed = true;
call.cancel();
}
@Override public boolean isDisposed() {
return disposed;
}
}
}
CallExecuteObservable类的核心就是subscribeActual()方法,当Observer订阅Observable时会执行该方法,即调用subscribe()方法时。
在subscribeActual()方法里会进行网络请求,并将结果传递给Observer。
那为什么BodyObservable类对responseObservable要进一步封装呢?去里边找找答案:
final class BodyObservable<T> extends Observable<T> {
private final Observable<Response<T>> upstream;
BodyObservable(Observable<Response<T>> upstream) {
this.upstream = upstream;
}
// Observable订阅Observer时会执行该方法
@Override protected void subscribeActual( Observer<? super T> observer) {
// new BodyObserver<T>(observer),将RxJava订阅时,我们自定义的Observer重新封装
upstream.subscribe(new BodyObserver<T>(observer));
}
private static class BodyObserver<R> implements Observer<Response<R>> {
private final Observer<? super R> observer;
private boolean terminated;
BodyObserver(Observer<? super R> observer) {
this.observer = observer;
}
@Override public void onSubscribe(Disposable disposable) {
observer.onSubscribe(disposable);
}
// 将CallExecuteObservable中,observer.onNext(response)这一步拿到的请求结果进一步处理
@Override public void onNext(Response<R> response) {
// 请求成功
if (response.isSuccessful()) {
// 只将响应体发送给我们自定义的observer
observer.onNext(response.body());
} else {
terminated = true;
Throwable t = new HttpException(response);
try {
// 将异常信息发送给我们自定义的Observer
observer.onError(t);
} catch (Throwable inner) {
......
}
}
}
@Override public void onComplete() {
if (!terminated) {
observer.onComplete();
}
}
@Override public void onError(Throwable throwable) {
if (!terminated) {
observer.onError(throwable);
} else {
......
}
}
}
}
可以看到BodyObservable类的主要作用就是通过BodyObserver类增强我们自定义的observer功能,使其可以对CallExecuteObservable中observer.onNext(response)拿到的响应结果进一步处理,只取出响应体的数据发送给我们自定义的observer。
到这里数据适配器的主要任务就结束了,就是为整合RxJava做准备,调用Retrofit封装的OkHttpCall执行网络请求,并将结果发送给observer。
使用Java动态代理的目的就是要拦截被调用的java方法,然后解析这个java方法的注解,最后生成Request由OkHttp发送。
但还有些事情没搞清楚,那就是OkHttpCall,在CallExecuteObservable中执行它的call.execute()方法时,内部做了些什么,内部是如何通过OkHttp进行网络请求的。
④OkHttp网络请求
OkHttpCall的execute()同步请求方法:
OkHttpCall.java:
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if(executed) throw new IllegalStateException( "Already executed.");
executed = true;
call = rawCall;
if (call == null) {
call = rawCall = createRawCall(); //创建OkHttp的Call对象
}
}
if (canceled) {
call.cancel();
}
//call.execute()调用OkHttp的同步网络请求方法。然后parseResponse()解析请求结果
return parseResponse(call.execute());
}
OkHttpCall的enqueue()异步请求方法:
@Override public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
synchronized (this) {
if(executed) throw new IllegalStateException( "Already executed.");
executed = true;
call = rawCall;
if (call == null) {
call = rawCall = createRawCall(); //创建OkHttp的Call对象
}
}
if(canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
response = parseResponse( rawResponse); // 使用gson解析返回的数据
callback.onResponse(OkHttpCall.this, response); //先走适配器转换数据,然后走自定义callback
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
}
}
});
}
可见,OkHttpCall的execute()/enqueue()方法内部会构建OkHttp的Call对象并发起网络请求,这样Retrofit就和OkHttp关联上了。
⑤数据解析器
OkHttpCall的parseResponse()的作用就是使用Gson将响应体的JSON字符串转换成指定对象。
OkHttpCall.java:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody( rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
......
}
if (code == 204 || code == 205) {
......
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
T body = responseConverter.convert( catchingBody); //通过指定的数据解析器来解析响应体
return Response.success(body, rawResponse); // 返回请求结果
} catch (RuntimeException e) {
}
}
关键的就是responseConverter.convert( catchingBody),responseConverter就是通过配置Retrofit时设置的GsonConverterFactory数据解析器工厂得到的,对应的数据解析器就是GsonRequestBodyConverter。它通过Gson解析响应体,转换成指定类型的对象。如果响应体是加密的,可以在这里先做解密工作,再做Gson解析。
到这里Retrofit的工作原理基本就结束了,Retrofit就是让开发者通过接口注解的形式描述网络请求,然后解析接口,将网络请求封装到OkHttpCall里。数据适配器就是用Retrofit提供的OkHttpCall来组织网络请求,想怎么玩数据适配器自己决定就好了。数据解析器就相对简单了,把网络请求的结果转换成需要的格式。Retrofit、数据适配器、数据解析器,它们之间的职责划分很明确的,几乎没有业务上的耦合,完全是可插拔式的。
4.Retrofit结合RxJava使用
①首先在build.gradle文件中加入依赖:
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
compile 'io.reactivex2:rxandroid:2.0.1'
②将RetrofitService类中getPostInfo方法的返回值修改为Observable(被观察者):
public interface RetrofitService {
@GET("query")
Observable<PostInfo> getPostInfoRx( @Query("type") String type, @Query("postid") String postid);
}
③在创建Retrofit时添加RxJava支持:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.kuaidi100.com/")
.addConverterFactory( GsonConverterFactory.create())
.addCallAdapterFactory( RxJavaCallAdapterFactory.create()) // 支持RxJava
.build();
④获取被观察者:
RetrofitService service = retrofit.create( RetrofitService.class);
Observable<PostInfo> observable = service.getPostInfoRx("yuantong", "11111111111");
⑤订阅:
observable.subscribeOn(Schedulers.io()) // 在子线程中进行Http访问
.observeOn( AndroidSchedulers.mainThread()) // UI线程处理返回接口
.subscribe(new Observer<PostInfo>() {//订阅
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(PostInfo postInfo) {
Log.i("http返回:", postInfo.toString() + "");
}
});
在RxJava中,由于链式调用的影响,是被观察者订阅观察者。
5.Retrofit注解
①请求方法
在网络请求接口方法中,使用@GET注解,说明这是一个GET方法,当然也可以写成HTTP协议中的其他请求方法(比如POST、PUT、DELETE、HEAD等)。
②请求参数
(1)@Query()
@GET("query")
Call<PostInfo> getPostInfo(@Query("type") String type, @Query("postid") String postid);
相当于:
@GET(query?type=type&postid=postid)
Call<PostInfo> getPostInfo(@Query("type") String type, @Query("postid") String postid);
(2)@QueryMap
当参数很多的时候可以使用Map集合:
@GET("query")
Call<Book> getSearchBook(@QueryMap Map<String, String> parameters);
(3)@Path
用于替换url中的某些字段,当url中字段不确定时可以使用:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
id可以为任意字段,需要和@Path("id")中的字段保持一致,如果需要请求参数,也可以使用@Query拼接:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
(4)@Body
可以使用实体类作为请求体,Retrofit会自动转换:
@POST("users/new")
Call<User> createUser(@Body User user);
(5)@FormUrlEncoded/@Field
用于传送表单数据,注意在头部需要加上@FormUrlEncoded,first_name代表key,first代表value:
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
(6)@Multipart/@Part
用于上传文件:
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
(7)@Header/@Headers
用于设置请求头:
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
也可以通过@Headers设置:
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
同时Retrofit设计的目的有两个方面:
①请求前
可以统一配置网络请求头;
可以很方便得复用Request,或创建request。
②请求后
子线程需切换到UI线程,便于界面刷新;
返回数据可以解析为Java Bean,方便使用