GithubHelp home page GithubHelp logo

retrofitcodelearn's Introduction

RetrofitCodeLearn

Retrofit 源码分析 设计模式分析 心得

问题

  1. 为什么我们调用接口方法没有具体实现就能请求网络 ?
  2. Gson FastGson 等等 是如何转换的 Retrofit是怎样设计的 ?
  3. Rxjava 这些 CallAdapter 又是如何设计的 ?
  4. 为什么Retrofit的 Call的回调是在主线程中执行的 ?
  5. 我们在接口中声明的Call到底是谁 到底return了什么给我们调用 ?
  6. 通过动态代理学到了什么 ?

Retrofit 核心create

val service: GitHubService = retrofit.create(GitHubService::class.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();
              private final Object[] emptyArgs = new Object[0];

              @Override
              public @Nullable Object invoke(Object proxy, Method method, @Nullable 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);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
}

通过动态代理 代理Service接口

大致的实现思路

代码运行期间通过动态代理 jdk帮我们实现 servicec接口 并有了具体的实现 而实现的具体内容正好是 InvocationHandler.invoke(Object proxy, Method method, @Nullable Object[] args)中的代码,也就是loadServiceMethod(method).invoke(args);

帮我们生成的代理类大概就长这个样子

class ProxyClass implements GitHubService {
    
    InvocationHandler invocationHandler = new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
            return loadServiceMethod(method).invoke(args);
        }
    };
    
    @NotNull
    @Override
    public Call<Repo> listRepos(@NotNull String user) {
        return invocationHandler.invoke(this,this.getClass().getMethod("listRepos", String.class),user);
    }

}

一次正常的网络请求

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build()

val service: GitHubService = retrofit.create(GitHubService::class.java)

val call = service.listRepos("octocat")

call.enqueue(object : Callback<Repo?> {
    override fun onResponse(call: Call<Repo?>, response: Response<Repo?>) {
        Log.e("Main", "onResponse: ${response.body()?.name}" )
    }

    override fun onFailure(call: Call<Repo?>, t: Throwable) {

    }
})

经过Retrofit.create的代理后Service中定义的Call返回值实际上就是loadServiceMethod(method).invoke(args)

loadServiceMethod

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);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

在这里进行了接口方法的缓存处理 优化性能

ServiceMethod.parseAnnotations

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

RequestFactory.parseAnnotations(retrofit, method); 对声明的注解以及参数进行解析拼装

HttpServiceMethod.parseAnnotations

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    //...省略
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForBody<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
              continuationBodyNullable);
    }
}

默认情况下会return CallAdapted

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;
    }

    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
}

CallAdapted父类正好又是HttpServiceMethod 所以loadServiceMethod(method).invoke(args) 一路调用下来实际上是调用的HttpServiceMethodinvoke方法 如下

@Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
}

protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

这里的OKHttpCall是网络请求的真正实现 最终还是OkHttp

正好adapt是抽象方法 在 CallAdapted 中有实现 callAdapter.adapt(call);

CallAdapted中的callAdapted是从HttpServiceMethod.parseAnnotations这里传进来的

一路跟进

 CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);

最终找到

Retrofit.nexCallAdapter

public CallAdapter<?, ?> nextCallAdapter(
      @Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
    Objects.requireNonNull(returnType, "returnType == null");
    Objects.requireNonNull(annotations, "annotations == null");

    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
    //...省略
}

返回的adapter 又是从callAdapterFactories.get().get()中取出来的

继续查看callAdapterFactories的来源

发现这个是在Retrofit的构造方法中初始化的,也就是Builder.build()中

Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
}
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

这里的 callbackExecutor 在Androide的Okatfrorm 中有实现

static final class MainThreadExecutor implements Executor {
    private final Handler handler = new Handler(Looper.getMainLooper());

    @Override
    public void execute(Runnable r) {
        handler.post(r);
    }
}

是一个线程池 execute post到了主线程执行

默认有一个callAdapterFactories 在Platform中

Platform主要是对Java和Android的适配区分

最终找到DefaultCallAdapterFactory 也就是 platform.defaultCallAdapterFactories中的

注意之前 callAdapterFactories.get().get() 两次get 第一次是集合callAdapterFactories的get 第二次是 CallAdapter.Factory的get

public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
 
    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

      @Override
      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
}

最终 return 一个 CallAdapter

回归到callAdapter.adapt return ExecutorCallbackCall

这个Call 就是我们在Service中定义的最终使用的Call

也就是动态代理帮我们 return 的Call

class ProxyClass implements GitHubService {
    @NotNull
    @Override
    public Call<Repo> listRepos(@NotNull String user) {
        return new ExecutorCallbackCall<>(executor, call);
    }
}

得到最终的调用流程

Retrofit.loadServiceMethod(method) --> ServiceMethod.parseAnnotations(this, method) --> HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory) --> return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);

Retrofit.create --> Retrofit.loadServiceMethod(method).invoke(args) --> CallAdapted.invoke(args) --> adapt(call, args) --> callAdapter.adapt(call) --> return new ExecutorCallbackCall<>(executor, call);

ExecutorCallbackCall分析

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override
    public void enqueue(final Callback<T> callback) {
      Objects.requireNonNull(callback, "callback == null");

      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              callbackExecutor.execute(
                  () -> {
                    if (delegate.isCanceled()) {
                      // Emulate OkHttp's behavior of throwing/delivering an IOException on
                      // cancellation.
                      callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                      callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                  });
            }

            @Override
            public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }
    //...省略
}

callbackExecutor 是一个运行在主线程的线程池

delegate 就是在 invoke传入adapt时创建的 OkHttpCall 进行实际的网络请求

所以得出结论Retrofit的Call 的回调是运行主线程的,并且再声明Service接口时 return 的 Call 不是 OKhttp的Call 实际是 ExecutorCallbackCall

问题

Retrofit是如何适配RxJava的

通过 CallAdapter 通过判断方法的返回值类型 返回对应的 adapter

Gson这些是如何转换的

OkHttpCall.enqueue 中进行实际的网络请求操作 并对结果进行处理

通过 responseConverter.convert(catchingBody); 进行转换

心得

Converter.FactoryCallAdapter.Factory 的设计 让 Retrofit 有了更高的拓展性 这正是高内聚低耦合的实现案例

一切设计应面向接口编程 让实际的核心操作 通过接口抽取

动态代理的设计让方法的调用有了集中统一的管理

实际的应用

  1. mvp中 presenter层 调用 view 层 可能会遇到 activity关闭 view已经null释放 presenter还在调用 出现null异常 这里我们就可以通过动态代理在调用view层之前判断view是否为空 统一管理 无需每次调用都判断

如何实现

public abstract class BasePresenter<M extends IBaseModel, V extends IBaseView> {

    private V mProxyView;
    private M module;
    private WeakReference<V> weakReference;
    protected String TAG;

    public BasePresenter() {
        TAG = getClass().getSimpleName();
    }

    @SuppressWarnings("unchecked")
    public void attachView(V view) {
        weakReference = new WeakReference<>(view);
        mProxyView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(),view.getClass().getInterfaces(),new MvpViewHandler(weakReference.get()));
        if (this.module == null) {
            this.module = createModule();
        }
    }

    public void detachView() {
        this.module = null;
        if (isViewAttached()) {
            weakReference.clear();
            weakReference = null;
        }
    }

    protected boolean isViewAttached() {
        return weakReference != null && weakReference.get() != null;
    }

    protected V getView() {
        return mProxyView;
    }

    protected M getModule() {
        return module;
    }

    protected abstract M createModule();

    private class MvpViewHandler implements InvocationHandler {

        private IBaseView mvpView;

        MvpViewHandler(IBaseView mvpView) {
            this.mvpView = mvpView;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //如果V层没被销毁, 执行V层的方法.
            //P层不需要关注V层的返回值
            if (isViewAttached()) {
                return method.invoke(mvpView, args);
            } 
            return null;
        }
    }
}

将view层的调用委托给MvpViewHandler 最终 invoke时统一加上 判断调用 method的invoke

Rxjava 等 CallAdapter 的适配转换流程

动态代理最终 invoke 会调用到 HttpServiceMethod.invoke , 在 HttpServiceMethod.invoke 中会创建 OkHttpCall(这里是实际的Okhttp的请求)然后将 OkHttpCall 传递给 HttpServiceMethod.adapt 方法, 在 CallAdapter 中实现 调用的是 callAdapter.adapt . 这里的 callAdapter 实际上就是 Retrofit 初始化 addCallAdapterFactory 的一个 CallAdapter集合 , 在 nextCallAdapter 中遍历这个集合后调用 get 方法判断返回值是否为空 确定最终的 CallAdapter 然后调用该 CallAdapteradaptOkHttpCall 传入进行适配转换

Retrofit.create() 
    --> loadServiceMethod().invoke()
        --> ServiceMethod.parseAnnotations().invoke()
            --> HttpServiceMethod.parseAnnotations().invoke()
                --> new CallAdapted<>().invoke()
                    --> CallAdapted继承自HttpServiceMethod
                        --> HttpServiceMethod.invoke()
                            --> 创建OkHttpCall(实际的网络请求操作)
                                --> HttpServiceMetho.adapt(OkhHttpCall) //抽象方法 在子类(CallAdapted)有实现
                                    --> CallAdapted.adapt(OkhHttpCall)
                                        --> callAdapter.adapt(call)

callAdapter 获取流程

HttpServiceMethod.parseAnnotations()
    --> HttpServiceMethod.createCallAdapter();
        --> retrofit.callAdapter()
            --> Retrofit.nextCallAdapter()
                --> callAdapterFactories.get(i).get(returnType, annotations, this)
                    --> new CallAdapted<>(callAdapter)

callAdapterFactories是一个集合 泛型<CallAdapter.Factory> addCallAdapterFactory都会添加到这个集合中

CallAdapter.Factoryget 方法中 根据返回值类型 确定是否是要转换适配的方法

如果是 实现具体的 CallAdapter.adapt 将传进来的 OkHttpCall 进行适配

综上

public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T) Proxy.newProxyInstance(service.getClassLoader(),new Class<?>[] {service},new InvocationHandler() {
        @Override
        public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
            //CallAdapter.Factory.get()-->CallAdapter.adapt
            return callAdapterFactories.get(i).get(returnType, annotations, this).adapt(call)
        }
    });
}

Gson FastJson 等 Converter 流程

OkHttpCall 进行实际的网络请求操作

private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
        throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
}

callFactory 实际上是 Retrofit.client 时传入的OkHttpClient

public Builder client(OkHttpClient client) {
    return callFactory(Objects.requireNonNull(client, "client == null"));
}

public Builder callFactory(okhttp3.Call.Factory factory) {
    this.callFactory = Objects.requireNonNull(factory, "factory == null");
    return this;
}

requestFactoryServiceMethod.parseAnnotations() 时 进行解析 RequestFactory.parseAnnotations(retrofit, method);

主要作用就是解析 Service接口中定义的注解参数等

并最终构建出一个OKhttp的request对象

实际的请求 OkHttpCall.enqueue()

call.enqueue(
        new okhttp3.Callback() {
          @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
            Response<T> response;
            try {
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
              throwIfFatal(e);
              callFailure(e);
              return;
            }

            try {
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }

          @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) {
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }
        });

parseResponse()中进行格式转换

 T body = responseConverter.convert(catchingBody);

responseConverter 同样是在 HttpServiceMethod.parseAnnotations中获取并传参的

Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

与CallAdapter 的获取类似 是从 converterFactories中获取的

retrofitcodelearn's People

Contributors

zhao-yan-yan avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

Forkers

zzsakurazz

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.