拆Retrofit2.0 的create()方法流程

微信公众号:JueCode

Retrofit不用多介绍了,谁用谁知道。我在使用过程中会产生疑问:

1.声明的接口NetService怎么经过create就能调用发起网络请求?

2.接口中的方法可以返回Call,也可以返回其他类型,比如Observable,这之间有什么关系,或者经过怎样的转化过程?

带着这两个疑问去探索下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() {
                    private final Platform platform = Platform.get();

                    @Override
                    public Object invoke(Object proxy, Method method, Object... args)
                            throws Throwable {
                        // If the method is a method from Object then defer to normal invocation.
                        if (method.getDeclaringClass() == Object.class) {
                            return method.invoke(this, args);
                        }
                        if (platform.isDefaultMethod(method)) {
                            return platform.invokeDefaultMethod(method, service, proxy, args);
                        }
                        ServiceMethod serviceMethod = loadServiceMethod(method);
                        OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
                        return serviceMethod.callAdapter.adapt(okHttpCall);
                    }
                });
    }

我们的第一个疑问有解了,在create中会通过Java动态代理的方式来处理对方法的调用问题。这样说可能比较抽象,简单举个栗子,通过动态代理就会返回Call对象。


public interface MyService{

  @Get("info")

  Call<User> getUser();

}

重点是最后的三行代码。

1. ServiceMethod serviceMethod =(ServiceMethod)loadServiceMethod(method);

ServiceMethod官方解释:


Adapts an invocation of an interface method into an HTTP call

有四个重要的成员:


//封装call,默认是okHttpCall

this.callFactory = builder.retrofit.callFactory();      

//最著名的RxJava,默认是不支持,通过添加.addCallAdapterFactory(RxJavaCallAdapterFactory.create())增加对Obsevable的支持

this.callAdapter = builder.callAdapter;

//addConverterFactory(GsonConverterFactory.create())将服务器返回的response,提取出ResponseBody(json)转化为User

this.responseConverter = builder.responseConverter; 

// 负责解析API定义时每个方法的参数

this.parameterHandlers = builder.parameterHandlers;

2. okHttpCall = new OkHttpCall<>(serviceMethod, args);

OkHttpCall实现Call接口,主要会用到的方法execute和enqueue,一个同步一个异步。

@Override
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 {
                call = rawCall = createRawCall();
            } catch (IOException | RuntimeException e) {
                creationFailure = e;
                throw e;
            }
        }
    }

        if (canceled) {
            call.cancel();
        }

        return parseResponse(call.execute());
    }    

可以看出,会通过createRawCall创建okhttp,创建过程先通过serviceMethod创建request,request传入callFactory创建okhttp3.Call。最后通过okhttpCall调用execute,enqueue的调用过程类似,最后也是通过okhttp调用enqueue。

private okhttp3.Call createRawCall() throws IOException {
        Request request = serviceMethod.toRequest(args);
        okhttp3.Call call = serviceMethod.callFactory.newCall(request);

        if (call == null) {
            throw new NullPointerException("Call.Factory returned null.");
        }
        return call;
}

3. serviceMethod.callAdapter.adapt(okHttpCall)

有几个概念需要注意下:

responseType:这个返回的是关注的类型,比如Call ,返回的是User的类型

returnType:这个是接口中方法的返回类型,比如Call那么返回的就是Call类型

public interface CallAdapter<T> {
        Type responseType();

        <R> T adapt(Call<R> call);
        
        public abstract CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit);

protected static Type getParameterUpperBound(int index, ParameterizedType type) {
            return Utils.getParameterUpperBound(index, type);
        }

        protected static Class<?> getRawType(Type type) {
            return Utils.getRawType(type);
        }
    }

callAdapter是接口public interface CallAdapter的实现类

serviceMethod中的callAdapter通过callAdapter = createCallAdapter()创建

private CallAdapter createCallAdapter() {
        Type returnType = method.getGenericReturnType();
        if (Utils.hasUnresolvableType(returnType)) {
            throw methodError("Method return type must not include a type       variable or wildcard: %s", returnType);
        }

        if (returnType == void.class) {
            throw methodError("Service methods cannot return void.");
        }

        Annotation[] annotations = method.getAnnotations();
        try {
            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);
        }
    }

在retrofit中根据returnType从adapterFactories(List adapterFactories = new ArrayList<>();)中得到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;
            }

        }
        …….
    }

factories可以在初始化retrofit的时候添加,我们来看下默认的CallAdapter.Factory, 工厂模式,这个也是retrofit中大量使用的设计模式,在public interface Converter 接口中也会使用。DefaultCallAdapterFactory没有多少代码,重点看下get方法

1.默认的模式只支持Call这种returnType,所以一进来会判断是不是Call.class。

2.记下来会根据renturnType来获得responseType,也就是上面例子中Call中的User类型。

3.最后会new一个CallAdapter,因为默认的是支持Call这种returnType,因此在adapt方法中直接返回call。

    final class DefaultCallAdapterFactory extends CallAdapter.Factory {

        static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
        @Override
        public CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit) {

            if (getRawType(returnType) != Call.class) {
                return null;
            }

  final Type responseType =Utils.getCallResponseType(returnType);
            return new CallAdapter > () {
                @Override public Type responseType () {

                    return responseType;
                }

                @Override public Call adapt (Call call){
                    return call;

                }
            } ;
        }
    }

4.我们再简单看看RxJava2CallAdapterFactory

    public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
        ......

        @Override

        public CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit) {

            Class rawType = getRawType(returnType);

            ......

            return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,isSingle, isMaybe, false);
        }

    }

在RxJava2CallAdapter中,看到熟悉的adapt方法,方法会将call封装成Observable,最后我们就可以快乐的使用RxJava

    final class RxJava2CallAdapter implements CallAdapter {

        @Override
        public Type responseType() {

            return responseType;

        }

        @Override
        public Object adapt(Call call) {

            Observable > responseObservable = isAsync

                    ? new CallEnqueueObservable<>(call)

                    : new CallExecuteObservable<>(call);

            ……

            return observable;

        }

    }

当然还没完,我们在深入到Observable中一探究竟,我们看下异步CallEnqueueObservable的例子。可以看到实际执行还是通过call.enqueue(callback)执行。

    final class CallEnqueueObservable extends Observable {

        private final Call originalCall;

        CallEnqueueObservable(Call originalCall) {

            this.originalCall = originalCall;

        }

        @Override
        protected void subscribeActual(Observer>observer) {

            // Since Call is a one-shot type, clone it for each new observer.

            Call call = originalCall.clone();

            CallCallback callback = new CallCallback<>(call, observer);

            observer.onSubscribe(callback);

            call.enqueue(callback);

        }

        private static final class CallCallback implements Disposable, Callback {

            ......

        }

    }

到这里我们对create()方法的分析过程就结束了,Retrofit是通过Java动态代理实现对接口方法的调用处理,通过解析方法的注解和参数封装request,通过request去构造HttpCall,再根据CallAdapter Factory对Call进行代理,其实内部还是通过OkHttp的Call模式做实际工作。Retrofit中比较多的使用工厂模式,实现很好的解耦,很值得借鉴。这方面的文章可以借鉴http://www.jianshu.com/p/45cb536be2f4
谢谢!

扩展阅读:

https://blog.piasy.com/2016/06/25/Understand-Retrofit/

http://blog.csdn.net/lmj623565791/article/details/51304204

欢迎关注公众号:JueCode

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容