Retrofit源码解析(二)

来源:互联网 发布:黑格尔的哲学思想知乎 编辑:程序博客网 时间:2024/05/17 21:43

上节课我们留个问题咩有解决,ExecutorCallAdapterFactory这个类是用来干什么的?
老规矩,让我们查看源码!

ExecutorCallAdapterFactory(Executor callbackExecutor) {    this.callbackExecutor = callbackExecutor;//拿到执行器  }
@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<Object, Call<?>>() {      @Override public Type responseType() {        return responseType;      }      @Override public Call<Object> adapt(Call<Object> call) {        return new ExecutorCallbackCall<>(callbackExecutor, call);//这个接口很重要,代理和回调的桥接器,我会在下一节继续讲      }    };  }
 @Override public void enqueue(final Callback<T> callback) {      checkNotNull(callback, "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方法我相信使用过Retrofit的朋友们的疑惑都消除了,其实就是执行了异步操作但是通过执行器在主线程中修改UI界面。

也就是说Runnable里面的代码是在主线程中进行的,所以是可以在这里修改UI线程的!

也就是说Runnable里面的代码是在主线程中进行的,所以是可以在这里修改UI线程的!

也就是说Runnable里面的代码是在主线程中进行的,所以是可以在这里修改UI线程的!

说的更加通俗点就看下面的代码:

   Call<ResponseBody> call=RetrofitUtils.getInstance().getApiService().getCompleteBook();        call.enqueue(new Callback<ResponseBody>() {            @Override            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {                //主线程中进行的,可以修改UI界面                try {                    toast(response.body().string().toString());                } catch (IOException e) {                    e.printStackTrace();                }            }            @Override            public void onFailure(Call<ResponseBody> call, Throwable t) {                //主线程中进行的,可以修改UI界面            }        });

前面基本上把Retrofit构建和异步操作原理讲明白了,但是还有一个大家疑惑的地方在于我定义Retrofit的时候一般需要一个接口,里面写满了各种各样的带注解的方法,但是Retrofit是如何把GET,POST这样的请求辨识出来并且封装成一个Call的呢?

动态代理

让我们看一个例子:

public interface ApiService {    @Getter    String showTeacherName(String name);    @Setter    String showStudentName(String name);}
public class Main {    public static void main(String[] args) {        ApiService api= (ApiService) Proxy.newProxyInstance(ApiService.class.getClassLoader(), new Class[]{ApiService.class}, new InvocationHandler() {            @Override            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                System.out.println(args[0].toString());                Annotation[] annotations = method.getAnnotations();                System.out.println(annotations[0].annotationType());                return args[0].toString();            }        });        api.showStudentName("张三");        api.showTeacherName("刘老师");    }}

结果如图所示:

这里写图片描述

这里简单讲下动态代理的好处,动态代理和静态代理不同,不需要提前编译所以编译之前不会产生字节码,不占用内存;程序异常灵活省去大量重复写代码的时间;可以修改代码执行的内容,可以在方法调用前后增加自己的内容。但是在本文中最重要的是下面这一点

我们仔细观察这个接口里面的方法,注解是不一样的,GET SET,如果按照以前的思路,动态代理里面的方法都必须调用method.invoke(**),因为是要考虑不同的返回类型,但是这里遇到了一种极端状况,返回类型都一样!都是String,所以我们其实可以自定义返回的值,举个例子,我给别人写信,给我的爸爸妈妈,兄弟姐妹写的话我会分别写:亲爱的老爸,亲爱的老妈,亲爱的老弟等等,但是如果现在我只给我的女朋友写信,我就写:Dear Love,就不会再具体情况具体分析了,全部都是一样的。

举这个例子是为了做个铺垫,下一节我会详细讲述Retrofit是如何按照这个思路来封装Call的,我们下节课见。

原创粉丝点击