android面试(13)-retrofit

retrofit可以说是如今市面上最火的网络框架,最常用的大概就是retrofit+RxJava+okhttp框架,结合MVP设计模式的经典应用了吧,今天我们只讲retrofit,上一篇已经说过,retrofit的内部其实也是使用了okhttp的

1.使用方法:

(1)创建一个接口作为http请求的api接口

public interface Api {

    @GET("repos/{owner}/{repo}/contributors")
    Call contributorBySimpleGetCall(@Path("owner") String owner,@Path("repo") String repo);

}

(2)创建一个Retrofit的实例

(3)调用api接口

private void retrofitHttpGet() throws Exception{
    Retrofit retrofit=new Retrofit.Builder().baseUrl("")
            .build();

    Api api=retrofit.create(Api.class);
    Call responseBodyCall = api.contributorBySimpleGetCall("owner", "repo");
    responseBodyCall.enqueue(new Callback() {
        @Override
        public void onResponse(Call call, Response response) {
            Log.e("返回的数据是:",response.body().toString());
        }

        @Override
        public void onFailure(Call call, Throwable t) {

        }
    });
}

2.源码分析:

讲到retrofit的源码,就不得不提到一个很牛逼的概念,java当中的动态代理

每次我想到java的动态代理,我都会想到一个例子,打个比方,比如说,你喜欢一个美女,想给他表白,情书都写好了,但是你不敢给他,于是拜托我递给她,但是我也喜欢这个美女,所以我在给她情书的时候,在她面前说你是个渣男。在这个过程中,你就是委托类,我就是中介类,美女就勉强当做代理类吧,你委托我干一件事,我在干这件事的前后可以做一些其他的操作,这就是Java的动态代理的概念,接下来就用一个代码实例来说明一下:

public class DTDLTest {

    public static void main(String args[]) {
        //创建委托类实例
        WTLClass wtlClass=new WTLClass();
        //创建中介类实例
        ProxyHandler handler=new ProxyHandler(wtlClass);
        //动态创建代理类
        Subject subject= (Subject)Proxy.newProxyInstance(wtlClass.getClass().getClassLoader(), Subject.class.getInterfaces(), handler);
        //通过代理类对象调用代理类方法,实际上会转到invoke方法调用 
        subject.doSomething();
    }

    //创建委托类
    static class WTLClass implements Subject{
        @Override
        public void doSomething() {
            System.out.println("干一些事情");
        }
    }

    //委托类实现的接口
    interface Subject{
        void doSomething();
    }


    //创建中介类
    static class ProxyHandler implements InvocationHandler{

        private Object object;

        public ProxyHandler(Object o) {
            this.object=o;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("方法调用前干的事");
            Object object=method.invoke(proxy,args);
            System.out.println("方法调用前干的事");
            return object;
        }
    }
}

了解了动态代理之后,接下来就开始分析retrofit的源码了,retrofit的源码有点多,而且有点复杂,我还是先决定把它整个请求网络的流程先梳理一遍:

(1)通过解析 网络请求接口的注解 配置 网络请求参数

(2)通过 动态代理 生成 网络请求对象

(3)通过 网络请求适配器 将 网络请求对象 进行平台适配

(4)通过 网络请求执行器 发送网络请求

(5)通过 数据转换器 解析服务器返回的数据

(6)通过 回调执行器 切换线程(子线程 ->>主线程)

(7)用户在主线程处理返回结果

现在把上面的几个角色一一介绍一遍:

(1)网络请求执行器:也就是我们创建出来的Call对象,它的作用就是创建Http请求,而retrofit中默认使用的就是okhttp3.Call,所以我们知道这里的网络请求执行器其实就是在okhttp里面讲的Call;

(2)网络请求适配器:(CallAdapter),这个就是Call的适配器,因为retrofit要适配各种平台,Android,Rxjava、Guava和java8,所以在retrofit内部配置了四种CallAdapterFactory,ExecutorCallAdapterFactory(Android默认),GuavaCallAdapterFactory,java8CallAdapterFactory,RxjavaCallAdapterFactory,通过这些适配器,可以让retrofit兼容各种平台,适配各种应用场景;

(3)数据转换器 :服务器返回的数据各种各样,retrofit为我们封装了各类数据的转换器,将返回数据解析成我们需要的数据类型;

(4)回调执行器:它的主要作用就是线程转换,把子线程切换到主线程,将最后的okhttp的请求结果通过callbackExecutor使用handler回调给主线程;

接下来就一步步的分析了;

我们先从创建Retrofit对象开始说起,

Retrofit retrofit=new Retrofit.Builder().baseUrl("")
            .build();

这里很明显是通过build模式建立的,首先看看retrofit的构造器

Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
    List converterFactories, List adapterFactories,
    Executor callbackExecutor, boolean validateEagerly) {
  this.callFactory = callFactory;
  this.baseUrl = baseUrl;
  this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
  this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
  this.callbackExecutor = callbackExecutor;
  this.validateEagerly = validateEagerly;
}
这里可以看出,创建一个retrofit的标准就是配置好一些参数,即:
serviceMethod:包含所有网络请求信息的对象 baseUrl:网络请求的url地址 callFactory:网络请求工厂 adapterFactories:网络请求适配器工厂的集合 converterFactories:数据转换器工厂的集合 callbackExecutor:回调方法执行器
再看他的Builder方法
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());
}
这里看出Builder设置了默认的
  • 平台类型对象:Android
  • 网络请求适配器工厂:CallAdapterFactory
下面的baseurl不用看源码就知道是配置网络请求的Url地址;
接下来看build方法
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 adapterFactories = new ArrayList<>(this.adapterFactories);
  adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

  // Make a defensive copy of the converters.
  List converterFactories = new ArrayList<>(this.converterFactories);

  return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
      callbackExecutor, validateEagerly);
}
这里就是将上述设置的变量统一配置给retrofit对象;

接下来就是创建网络请求接口的实例
Api api=retrofit.create(Api.class);
看看里面的create方法
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
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);
        }
      });
}
看看,有木有很熟悉的感觉,没错,就是上面说的java动态代理的写法,所以我们就直接看它最重要的方法,invoke方法,在invoke方法里有最重要的三行代码;
ServiceMethod serviceMethod = loadServiceMethod(method);
          
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod. callAdapter.adapt(okHttpCall) ;我们一行行的来看,首先看到的是ServiceMethod这个类,那么ServiceMethod到底是个上面玩意儿呢?
先看它是怎么来的,看loadServiceMethod()方法:
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;
}
这里有这么一句
result = new ServiceMethod.Builder(this, method).build();
ServiceMethod也是通过builder模式构建的;
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;
}
可见主要是将一些网络请求参数传入到构造器中
public Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
 this.methodAnnotations = method.getAnnotations();
  this.parameterTypes = method.getGenericParameterTypes();
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}
builder方法中是做了一些事情的,我们知道我们先写了一个网络请求接口类,在接口里我们使用了注释来确定了一些网络请求的信息,比如是使用get方法,请求的url地址,还有方法的参数,这里的builder方法就是获取api接口中的信息。
这里我们大致可以猜到,ServiceMethod就是一个封装了网络请求的参数的类,一个ServiceMethod对应网络请求接口的一个方法。
再来看第二句:
// 获取网络请求接口方法里的注释 this.methodAnnotations = method.getAnnotations(); // 获取网络请求接口方法里的参数类型 this.parameterTypes = method.getGenericParameterTypes(); //获取网络请求接口方法里的注解内容 this.parameterAnnotationsArray = method.getParameterAnnotations();


作者:Carson_Ho
链接:https://www.jianshu.com/p/0c055ad46b6c
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
// 获取网络请求接口方法里的注释 this.methodAnnotations = method.getAnnotations(); // 获取网络请求接口方法里的参数类型 this.parameterTypes = method.getGenericParameterTypes(); //获取网络请求接口方法里的注解内容 this.parameterAnnotationsArray = method.getParameterAnnotations();


作者:Carson_Ho
链接:https://www.jianshu.com/p/0c055ad46b6c
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
这里就是通过上面构造好的ServiceMethod创建出网络请求的执行器;
// 获取网络请求接口方法里的注释 this.methodAnnotations = method.getAnnotations(); // 获取网络请求接口方法里的参数类型 this.parameterTypes = method.getGenericParameterTypes(); //获取网络请求接口方法里的注解内容 this.parameterAnnotationsArray = method.getParameterAnnotations();


作者:Carson_Ho
链接:https://www.jianshu.com/p/0c055ad46b6c
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

// 获取网络请求接口方法里的注释 this.methodAnnotations = method.getAnnotations(); // 获取网络请求接口方法里的参数类型 this.parameterTypes = method.getGenericParameterTypes(); //获取网络请求接口方法里的注解内容 this.parameterAnnotationsArray = method.getParameterAnnotations();


作者:Carson_Ho
链接:https://www.jianshu.com/p/0c055ad46b6c
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

第三句:

 return serviceMethod.callAdapter.adapt(okHttpCall);
将第二步创建的 OkHttpCall对象传给第一步创建的 serviceMethod对象中对应的网络请求适配器工厂的 adapt()

这里我们就可以总结一下,Retrofit.create()方法就是通过Java动态代理,获取到网络请求接口里的参数,创建出一个okhttpcall的网络请求执行器;

接下来的事情就是通过okhttpcall对象进行网络请求,这里的操作和okhttp的操作是相同的,可以参照我的上一篇博客结合来看;




你可能感兴趣的:(android,android面试题)