美文网首页Android Http
Android网络之Retrofit2.0使用和解析

Android网络之Retrofit2.0使用和解析

作者: 静默加载 | 来源:发表于2016-07-12 10:48 被阅读865次

    个人博客地址 http://dandanlove.com/

    Android网络之Retrofit2.0使用和解析

    Retrofit2在项目中的使用

    Android studio项目添加依赖

    javacompile 'com.squareup.retrofit2:retrofit:2.0.1'

    项目中使用样例

    定义HTTP API使用接口

    javapublic interface GitHubService { 
          @GET("users/{user}/repos") 
          Call<List<Repo>> listRepos(@Path("user") String user);
    }
    
    • 通过在接口上添加注解的方式来表示如何处理网络请求。
    • Retrofit支持5中类型的注解:GET,POST,PUT,DELETE和HEAD.
    • 可以使用不带参数的url @GET("users/list"),也可以使用带参数的url @GET("users/list?sort=desc")

    构造Retrofit实例

    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();
    GitHubService service = retrofit.create(GitHubService.class);
    

    创建同步或异步HTTP请求到远程网络服务器

    Call<List<Repo>> repos = service.listRepos("octocat");
    

    定制数据类型转换器

    • Gson: com.squareup.retrofit2:converter-gson
    • Jackson: com.squareup.retrofit2:converter-jackson
    • Moshi: com.squareup.retrofit2:converter-moshi
    • Protobuf: com.squareup.retrofit2:converter-protobuf
    • Wire: com.squareup.retrofit2:converter-wire
    • Simple XML: com.squareup.retrofit2:converter-simplexml
    • Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars
    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com")
        .addConverterFactory(GsonConverterFactory.create())
        .build();
    
    GitHubService service = retrofit.create(GitHubService.class);
    

    Retrofit使用扩展

    自定义Gson类型转换器

    /**
    {
        "resultcode":0,
        "resultmsg":"请求成功",
        "result":{}
    }
    */
    public class Wrapper {
        public int resultcode ;
        public String resultmsg ;
        public Object result ;
        public static class JsonAdapter implements JsonDeserializer<Wrapper> {
            @Override
            public Wrapper deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                try {
                    String jsonRoot = json.getAsJsonObject().toString() ;
                    Wrapper wrapper = new Wrapper() ;
                    JSONObject jsobRespData = new JSONObject(jsonRoot) ;
                    wrapper.resultcode = jsobRespData.getInt("resultcode") ;
                    wrapper.resultmsg = jsobRespData.getString("resultmsg") ;
                    wrapper.result = jsobRespData.get("result") ;
                    return wrapper;
                } catch (JSONException e) {
                    throw new JsonParseException(e) ;
                }
            }
        }
    
    }
    

    添加到Retrofit当中

    Gson gson = new GsonBuilder()
                .registerTypeAdapter(Wrapper.class, new Wrapper.JsonAdapter())
                .create() ;
    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();
    
    GitHubService service = retrofit.create(GitHubService.class);      
    

    请求时添加head信息

    在定义请求接口时添加:

    @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);
    
    @GET("user")
    Call<User> getUser(@Header("Authorization") String authorization)
    
    Retrofit依赖

    如果所示在Retrofit2.0中只支持okhttp,所以另一种方法是在okhttp的拦截器中addheader。

    Retrofit2源码解析

    Retrofit请求框架实现了高度的解耦,通过解析注解的得到的代理类生成http请求,然后将请求交给OkHttp。通过在Retrofit创建时生成的Converter再将OkHttp返回的数据进行类型转换得到自己需要的数据。现在Rxjava响应式编程已经广泛应用,在使用Retrofit时也会结合RxJava使编码更加简单、高效。

    一张图简单描述一下Retrofit的工作原理:


    Retrofit工作原理

    定义网络请求接口

    public interface GitHubService {
         @GET("users/{user}/repos")
         Call<List<Repo>> listRepos(@Path("user") String user);
    }
    

    创建Retrofit实例

    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com")
        //支持RxJava
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .addConverterFactory(ByteArrayConverterFactory.create())
        .addConverterFactory(JSONObjectResponseConverterFactory.create())
        .addConverterFactory(StringResponseConverterFactory.create())
        //支持对象转json串
        .addConverterFactory(GsonConverterFactory.create())
        .build();
    
    • 设置BaseUrl
    • 添加CallAdapterFactory
    • 添加converterFactory
    • 此时也可以设置自定义的okHttpclient

    接下来我们看

    GitHubService service = retrofit.create(GitHubService.class);
    

    Retrofit.create方法的详细介绍

    public <T> T create(final Class<T> service) {
        //判断定义的接口服务是否可用
        Utils.validateServiceInterface(service);
        if (validateEagerly) {
          eagerlyValidateMethods(service);
        }
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
              //判断Android,IOS,java8
              private final Platform platform = Platform.get();
    
              @Override public Object invoke(Object proxy, Method method, Object... args)
                  throws Throwable {
                //如果是对象里的方法直接调用
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                /**
                * 对java8做兼容,android和ios值恒为false
                */
                if (platform.isDefaultMethod(method)) {
                  return platform.invokeDefaultMethod(method, service, proxy, args);
                }
                //主要看这三行代码
                /**
                * 1、生成获取缓存中的method对应的ServiceMethod或者生产method对应的ServiceMethod
                * 2、生成OkHttpCall的实例
                * 3、根据生成的ServiceMethod实例中的callAdapter对象,调用callAdapter.adapt方法创建
                * 对应的Observable
                */
                ServiceMethod serviceMethod = loadServiceMethod(method);
                OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.callAdapter.adapt(okHttpCall);
              }
            });
      }
    

    Platfrom的获取 Platfrom

    class Platform {
        //这个方法Android中为Plafrom默认的
        //Java8返回的是method.isDefault(),熟悉Java8的都知道这是Java8的新特性。。
        boolean isDefaultMethod(Method method) {
            return false;
        }
        //这个方法Android中有自己默认的实现MainThreadExecutor
        Executor defaultCallbackExecutor() {
            return null;
        }
        static class Android extends Platform {
            @Override 
            public Executor defaultCallbackExecutor() {
                return new MainThreadExecutor();
            }
    
            @Override 
            CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
                return new ExecutorCallAdapterFactory(callbackExecutor);
            }
            //Rx默认请求方式都是同步请求,所以我们在发出请求和请求结果回来的时候切换线程
            static class MainThreadExecutor implements Executor {
                private final Handler handler = new Handler(Looper.getMainLooper());
                @Override 
                public void execute(Runnable r) {
                    handler.post(r);
                }
            }
        }
    }
    

    ServiceMethod对象的生成

    先看一张我debug时候的ServiceMethod的图 ServiceMethod

    ServiceMethod的获取

    /**Retrofit.java
    * 首先从serviceMethodCache缓存中获取,如果为null则创建
    */
    ServiceMethod loadServiceMethod(Method method) {
        ServiceMethod result;
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            result = new ServiceMethod.Builder(this, method).build();
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }
    

    ServiceMethod的创建

    final class ServiceMethod<T> {
        //部分代码省略
        ServiceMethod(Builder<T> builder) {
            this.callFactory = builder.retrofit.callFactory();
            this.callAdapter = builder.callAdapter;
            this.baseUrl = builder.retrofit.baseUrl();
            this.responseConverter = builder.responseConverter;
            this.httpMethod = builder.httpMethod;
            this.relativeUrl = builder.relativeUrl;
            this.headers = builder.headers;
            this.contentType = builder.contentType;
            this.hasBody = builder.hasBody;
            this.isFormEncoded = builder.isFormEncoded;
            this.isMultipart = builder.isMultipart;
            this.parameterHandlers = builder.parameterHandlers;
        }
        static final class Builder<T> {
            public Builder(Retrofit retrofit, Method method) {
            this.retrofit = retrofit;
            this.method = method;
            this.methodAnnotations = method.getAnnotations();
            this.parameterTypes = method.getGenericParameterTypes();
            this.parameterAnnotationsArray = method.getParameterAnnotations();
        }
    
            public ServiceMethod build() {
                //创建CallAdapter<?>
                callAdapter = createCallAdapter();
                responseType = callAdapter.responseType();
                if (responseType == Response.class || responseType == okhttp3.Response.class) {
                 throw methodError("'"
                     + Utils.getRawType(responseType).getName()
                     + "' is not a valid response body type. Did you mean ResponseBody?");
                }
                //创建Converter<ResponseBody, T>
                responseConverter = createResponseConverter();
                for (Annotation annotation : methodAnnotations) {
                 parseMethodAnnotation(annotation);
                }
                /********/
                return new ServiceMethod<>(this);
            }
            
            private CallAdapter<?> createCallAdapter() {
                Type returnType = method.getGenericReturnType();
                /*******/
                Annotation[] annotations = method.getAnnotations();
                try {
                    //调用retrofit中的方法进行创建
                    return retrofit.callAdapter(returnType, annotations);
                } catch (RuntimeException e) { // Wide exception range because factories are user code.
                    throw methodError(e, "Unable to create call adapter for %s", returnType);
                }
            }
            private Converter<ResponseBody, T> createResponseConverter() {
                Annotation[] annotations = method.getAnnotations();
                try {
                    //调用retrofit中的方法进行创建
                    return retrofit.responseBodyConverter(responseType, annotations);
                } catch (RuntimeException e) { // Wide exception range because factories are user code.
                    throw methodError(e, "Unable to create converter for %s", responseType);
                }
            }
        }
    }
    
    CallAdapter的创建
    public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
        return nextCallAdapter(null, returnType, annotations);
    }
    
    public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
        checkNotNull(returnType, "returnType == null");
        checkNotNull(annotations, "annotations == null");
        int start = adapterFactories.indexOf(skipPast) + 1;
        for (int i = start, count = adapterFactories.size(); i < count; i++) {
            CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
            if (adapter != null) {
                return adapter;
            }
        }
        /********************/
    }
    

    在创建Retrofit的时候我们添加过.addCallAdapterFactory(RxJavaCallAdapterFactory.create()),这是我们会调用RxJavaCallAdapterFactory.get 方法获取CallAdapter,通过源代码我们可以找到其返回的是new SimpleCallAdapter(observableType, scheduler)

    Converter的创建
    public <T> Converter<T, RequestBody> requestBodyConverter(Type type,
       Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {
       return nextRequestBodyConverter(null, type, parameterAnnotations, methodAnnotations);
    }
    
    public <T> Converter<T, RequestBody> nextRequestBodyConverter(Converter.Factory skipPast,
        Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {
        checkNotNull(type, "type == null");
        checkNotNull(parameterAnnotations, "parameterAnnotations == null");
        checkNotNull(methodAnnotations, "methodAnnotations == null");
        int start = converterFactories.indexOf(skipPast) + 1;
        for (int i = start, count = converterFactories.size(); i < count; i++) {
            Converter.Factory factory = converterFactories.get(i);
            Converter<?, RequestBody> converter =
                factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this);
            if (converter != null) {
                //noinspection unchecked
                return (Converter<T, RequestBody>) converter;
            }
        }
        /******/
    }
    

    相同的在创建Retrofit的时候我们也添加过许多的ConverterFactory,在寻找相匹配的Converter时我们是通过遍历在寻找到第一个合适的Converter返回。什么叫做合适的Converter,即该ConverterFactory能产生出匹配服务接口注解和返回类型。

    retrofit的构造器中默认添加的适配器和转化器
    public static final class Builder {
        private Platform platform;
        private okhttp3.Call.Factory callFactory;
        private HttpUrl baseUrl;
        private List<Converter.Factory> converterFactories = new ArrayList<>();
        private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
        private Executor callbackExecutor;
        private boolean validateEagerly;
    
        Builder(Platform platform) {
          this.platform = platform;
          // Add the built-in converter factory first. This prevents overriding its behavior but also
          // ensures correct behavior when using converters that consume all types.
          //自动回添加加默认的转化器
          converterFactories.add(new BuiltInConverters());
        }
        /****************/
        public Retrofit build() {
          if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
          }
    
          okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) {
            callFactory = new OkHttpClient();
          }
    
          Executor callbackExecutor = this.callbackExecutor;
          if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
          }
    
          // Make a defensive copy of the adapters and add the default Call adapter.
          List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
          //添加一个默认的适配器(Android、IOS、Java8)
          adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
          // Make a defensive copy of the converters.
          List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    
          return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
              callbackExecutor, validateEagerly);
        }
    
    

    具体怎么从Factory中获取对应的Converter和Adapter我们从代码中可以直观的看到。

    OkHttpCall的创建

    OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
       this.serviceMethod = serviceMethod;
       this.args = args;
    }
    

    网络请求

    请求的准备

    serviceMethod.callAdapter.adapt(okHttpCall) 对应SimpleCallAdapter.adapt

    static final class SimpleCallAdapter implements CallAdapter<Observable<?>> {
        private final Type responseType;
        private final Scheduler scheduler;
        SimpleCallAdapter(Type responseType, Scheduler scheduler) {
            this.responseType = responseType;
            this.scheduler = scheduler;
        }
        @Override public Type responseType() {
            return responseType;
        }
        @Override public <R> Observable<R> adapt(Call<R> call) {
            //创建请求的观察者,返回我们需要的Ovservable
            Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) //
              .lift(OperatorMapResponseToBodyOrError.<R>instance());
            if (scheduler != null) {
                return observable.subscribeOn(scheduler);
            }
            return observable;
        }
    }
    
    static class Android extends Platform {
        @Override
        public Executor defaultCallbackExecutor() {
            return new MainThreadExecutor();
        }
        @Override
        CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
            return new ExecutorCallAdapterFactory(callbackExecutor);
        }
        static class MainThreadExecutor implements Executor {
            private final Handler handler = new Handler(Looper.getMainLooper());
            @Override
            public void execute(Runnable r) {
                handler.post(r);
            }
        }
    }
    /*
    * 因为默认的执行线程为主线程,所以我们要切换到subscribeOn(Schedulers.io())线程从而达到异步的目的。
    * 然后通过observeOn(AndroidSchedulers.mainThread())将线程切回UI线程。
    * 当Okhttp请求完数据并进行相应的convert之后,就可以在UI处理相应的逻辑。
    */
    service.listRepos("octocat")
    .observeOn(AndroidSchedulers.mainThread())
    .subscribeOn(Schedulers.io())
    .subscribe(list->{ 
        if(list!=null){      
        //TODO 取得数据后逻辑处理     
        }     
    });
    

    请求的发起

    回到CallAdapt方法,创建Observable,而new CallOnSubscribe<>(call)生成了一个OnSubscribe()的实例,而OnSubscribe继承自Action1,其只包含一个call()方法,而这个call是在CallOnSubscribe中实现:

    static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
        private final Call<T> originalCall;
        CallOnSubscribe(Call<T> originalCall) {
        this.originalCall = originalCall;
        }
        @Override public void call(final Subscriber<? super Response<T>> subscriber) {
            // Since Call is a one-shot type, clone it for each new subscriber.
            Call<T> call = originalCall.clone();
    
            // Wrap the call in a helper which handles both unsubscription and backpressure.
            RequestArbiter<T> requestArbiter = new RequestArbiter<>(call, subscriber);
            subscriber.add(Subscriptions.create(requestArbiter));
            subscriber.setProducer(requestArbiter);
        }
    }
    

    首先clone了一份Call,然后生成了RequestArbiter,他继承自AtomicBoolean,实现了Subscription, Producer接口,Producer只有一个request方法;一般实现该接口的类,都会包含一个Subscriber对象和一个待处理的数据:

    static final class RequestArbiter<T> extends AtomicBoolean implements Action0,
        Producer {
        private final Call<T> call;
        private final Subscriber<?super Response<T>> subscriber;
        RequestArbiter(Call<T> call, Subscriber<?super Response<T>> subscriber) {
            this.call = call;
            this.subscriber = subscriber;
        }
        @Override
        public void request(long n) {
            if (n < 0) {
                throw new IllegalArgumentException("n < 0: " + n);
            }
            if (n == 0) {
                return; // Nothing to do when requesting 0.
            }
            if (!compareAndSet(false, true)) {
                return; // Request was already triggered.
            }
            try {
                //进行网络请求
                Response<T> response = call.execute();
                if (!subscriber.isUnsubscribed()) {
                    subscriber.onNext(response);
                }
            } catch (Throwable t) {
                Exceptions.throwIfFatal(t);
                if (!subscriber.isUnsubscribed()) {
                    subscriber.onError(t);
                }
                return;
            }
            if (!subscriber.isUnsubscribed()) {
                subscriber.onCompleted();
            }
        }
    
        @Override
        public void call() {
            call.cancel();
        }
    }
    
    

    请求的执行

    回顾创建Retrofit.create()代码中serviceMethod.callAdapter.adapt(okHttpCall),所以上面的call.execute() 就是OkHttpCall.execute

    public Response<T> execute() throws IOException{
        okhttp3.Call call;
        synchronized (this) {
            if ( executed )
                throw new IllegalStateException( "Already executed." );
            executed = true;
            if ( creationFailure != null ){
                if ( creationFailure instanceof IOException ){
                    throw (IOException) creationFailure;
                } else {
                    throw (RuntimeException) creationFailure;
                }
            }
            call = rawCall;
            if ( call == null ){
                try {
                    //获取okhttp实例
                    call = rawCall = createRawCall();
                } catch ( IOException | RuntimeException e ) {
                    creationFailure = e;
                    throw e;
                }
            }
        }
        if ( canceled ){
            call.cancel();
        }
        //执行okhttp请求
        return(parseResponse( call.execute() ) );
    }
    
    private okhttp3.Call createRawCall() throws IOException{
        Request request = serviceMethod.toRequest( args );
        //serviceMethod构造中this.callFactory = builder.retrofit.callFactory();
        okhttp3.Call call = serviceMethod.callFactory.newCall( request );
        if ( call == null ){
            throw new NullPointerException( "Call.Factory returned null." );
        }
        return(call);
    }
    

    请求的OkHttpClient实例获取

    public okhttp3.Call.Factory callFactory() {
        return callFactory;
    }
    public Builder callFactory(okhttp3.Call.Factory factory) {
        this.callFactory = checkNotNull(factory, "factory == null");
        return this;
    }
    //使用自定义OkHttpClient
    public Builder client(OkHttpClient client) {
        return callFactory(checkNotNull(client, "client == null"));
    }
    
    public Retrofit build(){
        if ( baseUrl == null ){
            throw new IllegalStateException( "Base URL required." );
        }
        okhttp3.Call.Factory callFactory = this.callFactory;
        //没有自定义OkHttpClient,则会新创建一个
        if ( callFactory == null ){
            callFactory = new OkHttpClient();
        }
        Executor callbackExecutor = this.callbackExecutor;
        if ( callbackExecutor == null ){
            callbackExecutor = platform.defaultCallbackExecutor();
        }
        List<CallAdapter.Factory> adapterFactories = new ArrayList<>( this.adapterFactories );
        adapterFactories.add( platform.defaultCallAdapterFactory( callbackExecutor ) );
        List<Converter.Factory> converterFactories = new ArrayList<>( this.converterFactories );
        return(new Retrofit( callFactory, baseUrl, converterFactories, adapterFactories,
                     callbackExecutor, validateEagerly ) );
        }
    }
    

    请求结果的处理

    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 ){
            try {
                ResponseBody bufferedBody = Utils.buffer( rawBody );
                return(Response.error( bufferedBody, rawResponse ) );
            } finally {
                rawBody.close();
            }
        }
        if ( code == 204 || code == 205 ){
            return(Response.success( null, rawResponse ) );
        }
        ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody( rawBody );
        try {
            //使用Converter将返回结果转化为接口返回的数据格式类型
            T body = serviceMethod.toResponse( catchingBody );
            //包装成Response并返回
            return(Response.success( body, rawResponse ) );
        } catch ( RuntimeException e ) {
            catchingBody.throwIfCaught();
            throw e;
        }
    }
    

    还记得创建Observable时 Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)).lift(OperatorMapResponseToBodyOrError.<R>instance()); ,OperatorMapResponseToBodyOrError将包装的Response中的body取出来并进行发射。

    总结

    现在随着Rxjava响应式编程越来越多的程序猿使用,自己也开始接触和使用。Retrofit+Rxjava+okhttp是时下比较受欢迎的网络请求框架,其源代码并不是很多,其底层网络通信时交由 OkHttp来完成的,但是Retrofit运用了大量的设计模式,代码逻辑很清晰,笔者以前用的是AsyncHttpClient作为app的网络请求框架,其源码也没自己的研究过。但看完Retrofit代码之后觉得收获很大,建议如果感兴趣可以抽时间仔细的阅读。

    想阅读作者的更多文章,可以查看我 个人博客 和公共号:

    振兴书城

    相关文章

      网友评论

        本文标题:Android网络之Retrofit2.0使用和解析

        本文链接:https://www.haomeiwen.com/subject/gonjjttx.html