Retrofit源码学习笔记(1)一Retrofit

什么是Retrofit

     什么是Retrofit。官方的解释是,A type-safe HTTP client for Android and Java。一个适用于Android和java的类型安全的http客户端。事实上,Retrofit是对okHttp接口的封装,它的传输功能都是由okHttp所实现的。Retrofit利用注解的形式获得参数,并组装成uri传递给okHttp,将okHttp返回的结果进行解析,传递给用户。

 Retrofit的组成

 retrofit作为对okHttp接口的封装,其本身代码量并不大,但是代码结构却很精美。retrofit有几个比较重要的类。 
Retrofit:定义生成了Retroift的各项参数,包括类转换器,callAdapter等,同时Retroft的create方法能生成返回接口代理实体,实现接口所要求的功能。 
Call:向服务器发送一个请求,并返回响应。 
CallAdapter:对Call进行适配 
Converter:将http返回的数据转换为我们所需要的对象 
ServiceMethod:解析注释,并且获取参数,组成url 

 retrofit实例

MainActivity

 public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
          .addConverterFactory(GsonConverterFactory.create())
                .build();
        uerService repo = retrofit.create(uerService.class);
        Call<List<Contributor>> call = repo.contributorsByAddConverterGetCall("square", "retrofit");
        call.enqueue(new Callback<List<Contributor>>() {
            @Override
            public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
                List<Contributor> contributorList= response.body();
                for(Contributor contributor : contributorList) {
                    Log.d("login", contributor.getLogin());
                    Log.d("contributions", contributor.getContributions() + "");
                }
            }
            @Override
            public void onFailure(Call<List<Contributor>> call, Throwable t) {

            }
        });
    }
}


UserService

public interface uerService {
    @GET("repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributorsByAddConverterGetCall(@Path("owner") String owner, @Path("repo") String repo);
}

MainActivty中的代码结构很简单。我们可以一步一步走下来。


Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("https://api.github.com/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();  

这行代码定义生成了retrofit实例。baseUrl是域名,在接下来,我们可以获取接口中的注解和传入的参数,生成一个相对地址,然后将域名和相对地址结合起来,组成一个uri,发送给okhttp进行网络传输。这里我们使用了GsonConverter,他将传输过来的json数据转换成我们所需要的对象。

uerService repo = retrofit.create(uerService.class);

这行代码是retrofit的核心,create方法利用userService接口,然后返回一个uerService接口,这不是很奇怪吗?但是事实上,create方法返回的不单是一个接口,而是一个代理类。我们看一下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<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }
       显然上面使用了动态代理,create返回了接口的动态代理实例。什么是动态代理实例,简单来说,就是我们在代码运行的时候的时候传入一个接口,将接口封装成一个代理类,通过这个代理类得到的constructor函数生成动态代理实体。生成代理类实体有一个参数InvocationHandler,这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。

简而言之,invoke是在调用代理类的方法的时候调用的。在这里就是在下一行代码时会调用。

 

Call<List<Contributor>> call = repo.contributorsByAddConverterGetCall("square", "retrofit");

repo 调用uerservice接口的 repo.contributorsByAddConverterGetCall方法时,就会调用invoke方法。在invoke方法中,
程序生成了serivceMethod,serivceMethod用于对注释进行了解析生成了uri,方法最后返回了一个Call。

return serviceMethod.callAdapter.adapt(okHttpCall);
在这里,retrofit默认使用的事Android平台的callAdapter和E xecutor。所以我们查看Platform中Android平台中CallAdapterFactory生成CallAdaterFactor的代码。

  public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public <R> Call<R> adapt(Call<R> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }
可以看到
return serviceMethod.callAdapter.adapt(okHttpCall);
中的adapt调用的就是上段代码中的adapt函数。adapt中返回一个 ExectorCallbackCall实体。

        call.enqueue(new Callback<List<Contributor>>() {
            @Override
            public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
                List<Contributor> contributorList= response.body();
                for(Contributor contributor : contributorList) {
                    Log.d("login", contributor.getLogin());
                    Log.d("contributions", contributor.getContributions() + "");
                }
            }
            @Override
            public void onFailure(Call<List<Contributor>> call, Throwable t) {

            }
        });
这里的call事一个 ExectorCallbackCall实体,因此enqueue调用的就是ExectorCallbackCall的enqueue方法。我们看一下enqueue的源码:

  @Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              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(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

简而言之,在enqueue中,调用了delegate.enqueue方法。这里的delegate又是什么呢?追溯源码,我们可以知道这是在create中传入的OkHttpCall实例。OkHttpCall中所实现的enqueue方法封装调用了okhttp3.call方法,并在call的callback回调函数中调用了我们传入的callback回调函数,从而在传输正确和错误时,实现我们想要的操作。

retrofit对注解的解析

retrofit利用注解来传递参数的方式在我看来是很惊艳的。注解作为程序的元数据嵌入到程序,注解可以被解析工具或编译工具解析,我们可以将它理解为它是它所依附的类或者方法的一个内在属性。通过反射机制,我们在运行时通过字节码的方法可以获得注解信息,通过正则表达式对注解进行解析,并将传入的具体的参数来替换注解的占位符,从而获的完善的相对位置。
这些功能都是在serviceMethod中实现的。在serivceMethod类中的700多行代码中,关于注解的类型解析的代码就占了一半,从而使得retrofit能够实现各种的传递形式。
关于注解的详细介绍可以查看文档。




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值