Retrofit使用与解析
来源:互联网 发布:qq空间免费人气软件 编辑:程序博客网 时间:2024/05/02 02:23
Retrofit使用与解析
Retrofit是一个基于OkHttp的网络请求工具,其功能与Volley很相似,但是使用起来就很不一样。
Retrofit不用你去创建Request对象,每次指定Get还是Post等,它请求一个api只需你去调用一个Java方法。
使用
1.首先需要创建一个Retrofit对象,并指定域名:
//使用Builder模式构建对象private static final String BASE_URL = "http://xxx";//域名Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build();
Retrofit中Bulider类的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();//默认使用OkHttp } Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } // Make a defensive copy of the adapters and add the default Call adapter. List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories); adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); // Make a defensive copy of the converters. List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories); return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly); } }
2.之后,你只要根据api新建一个Java接口,并使用注解进行相关描述:
//Get请求public interface ElectricAPI { @GET("/api/v1/get/power/{lou}/{hao}") Call<Electric> electricData(@Path("lou") String lou,@Path("hao") String hao);}//Post请求public interface FeedBackAPI { @FormUrlEncoded @POST("/home/msg/0") Call<ResponseBody> feed(@Field("email") String email, @Field("content") String content);}//文件上传public interface FileUploadAPI { @Multipart @POST("api/v1/stuff/upload") Call<HttpResult<String>> uploadImage(@Part MultipartBody.Part file);}
3.最后只要通过retrofit对象创建Api对象了,并使用call对象进行请求和处理:
ElectricAPI api = retrofit.create(ElectricAPI.class);Call<Electric> call = api.electricData("12","122");// 请求数据,并且处理responsecall.enqueue(new Callback<Electric>() { @Override public void onResponse(Response<Electric> r) { System.out.println("请求成功"); } @Override public void onFailure(Throwable t) { }});
原理
从使用上可以看出,Retrofit其实是把一个Java接口对象翻译成一个Http请求,然后使用OkHttp请求。Retrofit使用的技术就是动态代理。
先看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)) {//默认返回false return platform.invokeDefaultMethod(method, service, proxy, args); } ServiceMethod serviceMethod = loadServiceMethod(method);//处理注解 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } }); }
接着是create方法的使用:
ElectricAPI api = retrofit.create(ElectricAPI.class);Call<Electric> call = api.electricData("12","122");
这里的api对象其实是一个动态代理,并不是实现了相关接口的对象。当api对象调用eletricData方法时,会被动态代理拦截,然后调用Proxy.newProxyInstance方法中的InvocationHandler对象的invoke方法。这里invoke方法传入三个对象,依次为代理对象(不用管)、method(这里是electricData方法),方法的参数(这里是”12”,”122”)。
这里Retrofit关心的就是method和它的参数args,接下去Retrofit就会用Java反射获取到electricData方法的注解信息,配合args参数,创建一个ServiceMethod对象。
ServiceMethod就像是一个处理器,传入Retrofit对象和Method对象,调用各个接口和解析器,最终生成一个Request,包含api 的域名、path、http请求方法、请求头、是否有body、是否是multipart等等。最后返回一个Call对象,Retrofit2中Call接口的默认实现是OkHttpCall,它默认使用OkHttp3作为底层http请求client。
接着看下上面的loadServiceMethod(Method method)方法
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; } private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
这里对解析请求进行了缓存,用于避免解析过慢。这里同样使用Builder模式构建ServiceMethod方法:
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)."); } } //处理api中的参数{ }占位符,真实参数在Java方法中传入,这里Retrofit会使用一个ParameterHandler来进行替换 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); }
执行Http请求
之前讲到,OkHttpCall是实现了Call接口的,并且是真正调用OkHttp3发送Http请求的类。OkHttp3发送一个Http请求需要一个Request对象,而这个Request对象就是从ServiceMethod的toRequest返回的。
Request toRequest(Object... args) throws IOException { RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart); @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types. ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers; //参数替换 int argumentCount = args != null ? args.length : 0; if (argumentCount != handlers.length) { throw new IllegalArgumentException("Argument count (" + argumentCount + ") doesn't match expected count (" + handlers.length + ")"); } for (int p = 0; p < argumentCount; p++) { handlers[p].apply(requestBuilder, args[p]); } return requestBuilder.build(); }
总的来说,OkHttpCall就是调用ServiceMethod获得一个可以执行的Request对象,然后等到Http请求返回后,再将response body传入ServiceMethod中,ServiceMethod就可以调用Converter接口将response body转成一个Java对象。
结合上面说的就可以看出,ServiceMethod中几乎保存了一个api请求所有需要的数据,OkHttpCall需要从ServiceMethod中获得一个Request对象,然后得到response后,还需要传入ServiceMethod用Converter转换成Java对象。
- Retrofit使用与解析
- retrofit与rxjava使用
- Retrofit与RxAndroid结合使用
- RxJava 与 Retrofit 基本使用
- Retrofit与Rxjava结合使用
- RxAndroid 与 Retrofit的使用
- 【Retrofit】Retrofit源码解析
- Retrofit 使用心得-json解析
- Retrofit 使用心得-xml解析
- 使用Retrofit获取json并解析
- 使用Gson解析Retrofit返回结果
- Retrofit网络库使用及解析
- Retrofit的使用和源码解析
- Retrofit解析
- retrofit解析
- Retrofit使用教程(三):Retrofit与RxJava初相逢
- Rxjava与retrofit的网络访问使用
- Retrofit的使用与基本的封装
- [生存志] 第141节 秦魏风俗掌故
- 列表框
- thinkphp比较完美的nginx配置
- Practice6_2_map_sort_by_comparator
- Hibernate环境配置
- Retrofit使用与解析
- hdu 1271 整数对(找规律)
- Ubuntu下gcc多版本共存和版本切换
- apache启动失败原因
- C+++多态性
- OpenGL ES总结(一)OpenGL 初识
- 操作系统概述
- 点云压缩入门篇(2)谷歌开源点云压缩draco平台编译
- minSdk> deviceSdk的问题