Retrofit详解(二)(Retrofit核心流程)

上一章已经介绍了Retrofit创建过程,这章介绍Retrofit Api Service创建与访问过程。

Retrofit 相比Volley等网络框架一个最大区别就是它只需要声明接口,就可以访问网络,刚刚使用的时候觉得很神奇,有木有。

要彻底理解底层实现访问,需要先来看看Java的动态代理。

public interface Subject {
    boolean login(String username, String password);
}

/**
 * 真实对象
 * @author Micky Liu
 *
 */
public class RealSubject implements Subject {

    @Override
    public boolean login(String username, String password) {
        System.out.println("username = " + username + ", passwd = " + password);
        return "MickyLiu".equals(username) && "123456".equals(password);
    }
}

/**
 * 动态代理类
 * @author Micky Liu
 *
 */
public class DynamicProxy implements InvocationHandler {

    /**需要代理的真实对象*/
    private Object subject;

    public DynamicProxy(Object subject) {
        this.subject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoke subject method \"" + method + "\"");
        boolean b = (boolean) method.invoke(subject, args);
        System.out.println("After invoked subject method \"" + method + "\"") ;
        return b;
    }
}

public class ProxySample {

    public static void main(String[] args) {
        //真实对象
        Subject realSubject = new RealSubject();

        //代理对象
        InvocationHandler handler  = new DynamicProxy(realSubject);

        //Proxy.newProxyInstance有三个参数
        //参数1:代理类加载器
        //参数2:真实对象实现的接口,这里用于关联代理对象和真实对象,确保代理对象里调用的方法是和真实对象同名的方法
        //参数3:代理对象
        Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler);
        boolean isSuccess = subject.login("MickyLiu", "123456");
        String result = isSuccess ? "login success" : "login failed";
        System.out.println(result);
    }
}
Retrofit除了使用上述的动态代理,还使用了Annotation即注解。在Retrofit中使用了自定义注解,如@POST @GET @Path @Query等,就像我们在接口中定义的:


@POST(Constants.URL_UPDATE_USER_LIST)
Observable<BaseResponse<List<User>>> updateUserList(@Query("userList") String userList);

看看我们前面使用过的代码:

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(getEndPoint(t))
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .client(clientBuilder.build())
        .build();
service = retrofit.create(t);

这章的重点 retrofit.create方法,它用来创建API Service接口,返回的对象是我们定义的Service,有了它我们就能直接调用service.updateUserList来访问网络接口了。来查看下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);
        }
      });
}

  首先调用validateServiceInterface只是调用了service.isInterface()方法判断是否这个对象是一个接口对象,不要问我isInterface()方法哪里来的,去jdk的Class类里找。

  往下是不是看见了前面介绍的动态代理?好吧,我明白了,Retrofit 不就是简单的使用动态代理,就实现了所谓只要声明接口就能访问网络了么。简单么?

  到这里我们已经知道retrofit 内部是怎么创建的了,接下来就看看它是怎么完成访问流程的。

  method.getDeclaringClass() == Object.class //这段代码用来判断当前方法是否是声明在Object中的访问

  platform.isDefaultMethod(method) //这段代码用来判断是否是默认代码,当Platform是Android的时候永远返回是false

    接下来的代码才是我们的重点了

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

看看ServiceMethodCache的定义,键:method对象, 值ServiceMethod对象,如果已经Map中缓存了这个method则直接取,没有则创建一个ServiceMethod存到map中并将这个serviceMethod返回。

private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();


ServiceMethod.Builder类:

public Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  this.methodAnnotations = method.getAnnotations();
  this.parameterTypes = method.getGenericParameterTypes();
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}

methodAnnotations是方法注解即POST(url),实际取到的值:@retrofit2.http.POST(value=UpdateUserList)]


parameterTypes 是参数类型的数组,实际取到的值:[class java.lang.String]


parameterAnnotationsArray 是参数注解即@Query(“userList”),实际取到的值:[@retrofit2.http.Query(encoded=false, value=userList)]


ServiceMethod.Builder.build()方法:

public ServiceMethod build() {
  callAdapter = createCallAdapter();
  responseType = callAdapter.responseType();
  if (responseType == Response.class || responseType == okhttp3.Response.class) {
    throw methodError("'"
        + Utils.getRawType(responseType).getName()
        + "' is not a valid response body type. Did you mean ResponseBody?");
  }
  responseConverter = createResponseConverter();

  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
  }

  if (httpMethod == null) {
    throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
  }

  if (!hasBody) {
    if (isMultipart) {
      throw methodError(
          "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
    }
    if (isFormEncoded) {
      throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
          + "request body (e.g., @POST).");
    }
  }

  int parameterCount = parameterAnnotationsArray.length;
  parameterHandlers = new ParameterHandler<?>[parameterCount];
  for (int p = 0; p < parameterCount; p++) {
    Type parameterType = parameterTypes[p];
    if (Utils.hasUnresolvableType(parameterType)) {
      throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
          parameterType);
    }

    Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
    if (parameterAnnotations == null) {
      throw parameterError(p, "No Retrofit annotation found.");
    }

    parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
  }

  if (relativeUrl == null && !gotUrl) {
    throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
  }
  if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
    throw methodError("Non-body HTTP method cannot contain @Body.");
  }
  if (isFormEncoded && !gotField) {
    throw methodError("Form-encoded method must contain at least one @Field.");
  }
  if (isMultipart && !gotPart) {
    throw methodError("Multipart method must contain at least one @Part.");
  }

  return new ServiceMethod<>(this);
}
返回的callAdapter为我们配置的“class retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$SimpleCallAdapter”

responseConverter为我们配置的“class retrofit2.converter.gson.GsonResponseBodyConverter”

parseMethodAnnotation用于将我们接口的method注解解析出来,保存在ServiceMethod.Builder类的成员变量里,以供后续使用。


接着的代码是通过获取参数注解解析我们的参数列表。


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);
  }
}
此处可以获取到returnType为rx.Observable<com.micky.retrofitsample.netservice.response.BaseResponse<java.util.List<com.micky.retrofitsample.model.User>>>,这不就是我们定义的接口返回类型么。
  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Android Retrofit是一种基于注解的网络请求库,旨在简化客户端与服务器之间的通信。它是Square公司开发的,使用了OkHttp作为网络请求的底层引擎。Retrofit核心可以总结为以下几点。 首先,Retrofit使用注解来定义网络请求接口。我们可以通过在接口方法上添加注解来指定请求的路径、请求方法、请求参数等。这样的设计使得我们可以更加清晰地定义和理解网络请求,并且减少了手动构建请求的工作量。同时,Retrofit还支持多种注解,如@Path、@Query、@FormUrlEncoded等,提供了更灵活的请求参数配置方式,以适应不同的业务场景。 其次,Retrofit通过使用动态代理技术,将我们定义的接口方法转换成实际的网络请求。在运行时,Retrofit会动态地生成一个实现了我们定义的接口的代理类,并在其中实现了请求的具体逻辑。这样,我们只需要调用接口方法即可发起网络请求,无需手动创建HTTP连接、处理请求和响应等操作。 再次,Retrofit支持多种数据解析器。它可以与Gson、Jackson等JSON解析库以及SimpleXml等XML解析库无缝集成,以方便地解析服务器返回的数据。我们只需要通过在Retrofit中配置相应的解析器,即可自动将服务器返回的JSON或XML数据解析为Java对象,简化了数据解析的过程。 最后,Retrofit内置了许多网络请求的功能和处理机制。例如,它支持同步和异步请求、文件上传和下载、请求拦截和重试、缓存等。并且,我们可以通过自定义OkHttpClient来配置网络请求的超时时间、连接池等参数,以满足不同的网络环境和需求。 总之,Android Retrofit是一个功能强大、灵活易用的网络请求库。它通过注解、动态代理和数据解析器等技术,简化了客户端与服务器之间的通信,降低了开发的复杂性和工作量,是Android开发中常用的网络请求框架之一。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值