Android Retrofit

1.Retrofit

Retrofit是基于okhttp封装的网络请求框架,网络请求的工作本质上是OkHttp完成,而Retrofit仅负责网络请求接口的封装。

OkHttp是安卓官方认证的网络请求框架,非常强大,但是它也有不少缺点:

①OkHttp配置网络请求是非常繁琐的,尤其是配置复杂网络请求body、请求头、参数的时候。

②数据解析过程需要用户手动拿到ResponseBody进行解析,难以复用。

③无法自动进行线程切换。

④如果存在嵌套网络请求,就会陷入“回调地狱”。

为了解决这些缺点,让网络请求在Android开发上易用,诞生了Retrofit框架,其实它本质上就是在OkHttp上套了层“壳子”,里面的请求还是基于OkHttp实现。

所以Retrofit封装OkHttp主要是以下几点:

①build模式创建网络请求基本配置

②用注解类组合HTTP网络请求

扫描二维码关注公众号,回复: 14503804 查看本文章

③提供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,方便使用

猜你喜欢

转载自blog.csdn.net/zenmela2011/article/details/126430654