当前位置: 首页 > news >正文

简约风格的网站/常州网站推广公司

简约风格的网站,常州网站推广公司,宿州网站建设公司,建网站深圳源码的分析将从基本的使用方法入手,分析retrofit的实现方案,以及其中涉及到的一些有趣的技巧。Android技术交流群653583088,欢迎大家加入交流,畅谈!本群有免费学习资料视频’简单使用定义HTTP APIpublic interface Git…
源码的分析将从基本的使用方法入手,分析retrofit的实现方案,以及其中涉及到的一些有趣的技巧。

Android技术交流群653583088,欢迎大家加入交流,畅谈!本群有免费学习资料视频

简单使用

定义HTTP API

 
public interface GitHubService {@GET("users/{user}/repos")Call<List<Repo>> listRepos(@Path("user") String user);
}
复制代码

创建Retrofit并生成API的实现

Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/").build();
GitHubService service = retrofit.create(GitHubService.class);
复制代码

调用API方法,生成Call

Call<List<Repo>> repos = service.listRepos("octocat");
复制代码

Retrofit的创建

retrofit实例的创建,使用了builder模式,从下面的源码中可以看出

public static final class Builder {Builder(Platform platform) {this.platform = platform;converterFactories.add(new BuiltInConverters());}public Builder() {// Platform.get()方法可以用于判断当前的环境this(Platform.get());}public Builder baseUrl(String baseUrl) {checkNotNull(baseUrl, "baseUrl == null");HttpUrl httpUrl = HttpUrl.parse(baseUrl);if (httpUrl == null) {throw new IllegalArgumentException("Illegal URL: " + baseUrl);}return baseUrl(httpUrl);}public Retrofit build() {if (baseUrl == null) {throw new IllegalStateException("Base URL required.");}okhttp3.Call.Factory callFactory = this.callFactory;if (callFactory == null) {callFactory = new OkHttpClient();// 新建Client,留到之后newCall什么的}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);}
}
复制代码

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() {// platform 可以分辨出你是在android,还是java8,又或者别的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.// 这里的invoke,Object方法都走这里,比如equals、toString、hashCode什么的if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);}// java8默认方法,1.8的新特性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);}});
}
复制代码

可以看出创建API使用了动态代理,根据接口动态生成的代理类,将接口的都转发给了负责连接代理类和委托类的InvocationHandler实例,接口方法也都通过其invoke方法来处理。 在invoke方法中,首先会通过Platform.get()方法判断出当前代码的执行环境,之后会先把Object和Java8的默认方法进行一个处理,也是在进行后续处理之前进行去噪。其中的关键代码其实就是最后三句,这也是这篇文章将要分析的 

创建ServiceMethod

erviceMethod<?, ?> loadServiceMethod(Method method) {// 从缓存里面取出,如果有的话,直接返回好了ServiceMethod<?, ?> result = serviceMethodCache.get(method);if (result != null) return result;synchronized (serviceMethodCache) {result = serviceMethodCache.get(method);if (result == null) {// 为null的话,解析方法的注解和返回类型、参数的注解he参数类型,新建一个ServiceMethodresult = new ServiceMethod.Builder<>(this, method).build();// ->// 新建的ServiceMethod加到缓存列表里面serviceMethodCache.put(method, result);}}return result;
}
复制代码

注解的解析

CallAdapterConverter等到后面再分析,这里先看看parseMethodAnnotation(annotation),功能和其名字一样,其对方法注解进行了解析

/*** 解析方法注解,呜啦啦* 通过判断注解类型来解析* @param annotation*/
private void parseMethodAnnotation(Annotation annotation) {if (annotation instanceof DELETE) {parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);} else if (annotation instanceof GET) {parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);} // 其他的一些方法注解的解析...
}
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {if (this.httpMethod != null) {// 已经赋值过了throw methodError("Only one HTTP method is allowed. Found: %s and %s.",this.httpMethod, httpMethod);}this.httpMethod = httpMethod;this.hasBody = hasBody;// value为设置注解方法时候,设置的值,官方例子中的users/{user}/repos or userif (value.isEmpty()) {return;}// 查询条件的一些判断...this.relativeUrl = value;this.relativeUrlParamNames = parsePathParameters(value);
}
`
复制代码

在解析注解时,先通过instanceof判断出注解的类型,之后调用parseHttpMethodAndPath方法解析注解参数值,并设置httpMethod、relativeUrl、relativeUrlParamNames等属性。 上面说了API中方法注解的解析,现在来看看方法参数注解的解析,这是通过调用parseParameterAnnotation方法生成ParameterHandler实例来实现的,代码比较多,这里挑选@Query来看看。

else if (annotation instanceof Query) {
Query query = (Query) annotation;
String name = query.value();
boolean encoded = query.encoded();
Class<?> rawParameterType = Utils.getRawType(type);// 返回基础的类
gotQuery = true;
// 可以迭代,Collection
if (Iterable.class.isAssignableFrom(rawParameterType)) {if (!(type instanceof ParameterizedType)) {throw parameterError(p, rawParameterType.getSimpleName()+ " must include generic type (e.g., "+ rawParameterType.getSimpleName()+ "<String>)");}ParameterizedType parameterizedType = (ParameterizedType) type;Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);// 返回基本类型Converter<?, String> converter =retrofit.stringConverter(iterableType, annotations);return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {// ArrayClass<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());// 如果是基本类型,自动装箱Converter<?, String> converter =retrofit.stringConverter(arrayComponentType, annotations);return new ParameterHandler.Query<>(name, converter, encoded).array();
} else {// OtherConverter<?, String> converter =retrofit.stringConverter(type, annotations);return new ParameterHandler.Query<>(name, converter, encoded);
}
复制代码

在@Query中,将分成Collection、array、other三种情况处理参数,之后根据这些参数,调用ParameterHandler中的Query静态类,创建出一个ParameterHandler实例。这样循环直到解析了所有的参数注解,组合成为全局变量parameterHandlers,之后构建请求时会用到 

OkHttpCall

ServiceMethod创建完成之后,我们来看看下一行代码中的OkHttpCall类,里面的包含了请求的执行和响应处理,我们来看看异步请求的做法

OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {this.serviceMethod = serviceMethod;this.args = args;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {if (executed) throw new IllegalStateException("Already executed.");executed = true;call = rawCall;failure = creationFailure;if (call == null && failure == null) {try {call = rawCall = createRawCall();// 创建OkHttp3.Call} catch (Throwable t) {failure = creationFailure = t;}}
}
if (failure != null) {callback.onFailure(this, failure);return;
}
if (canceled) {call.cancel();
}
call.enqueue(new okhttp3.Callback() {@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)throws IOException {Response<T> response;try {response = parseResponse(rawResponse);// ->} catch (Throwable e) {callFailure(e);return;}callSuccess(response);}@Override public void onFailure(okhttp3.Call call, IOException e) {try {callback.onFailure(OkHttpCall.this, e);} catch (Throwable t) {t.printStackTrace();}}private void callFailure(Throwable e) {try {callback.onFailure(OkHttpCall.this, e);} catch (Throwable t) {t.printStackTrace();}}private void callSuccess(Response<T> response) {try {callback.onResponse(OkHttpCall.this, response);} catch (Throwable t) {t.printStackTrace();}}
});
}
private okhttp3.Call createRawCall() throws IOException {Request request = serviceMethod.toRequest(args);// 根据ParameterHandler组装Request.Builder,生成Requestokhttp3.Call call = serviceMethod.callFactory.newCall(request);// Retrofit中创建的new OkHttpClient().newCall(request)...return call;
}
复制代码

CallAdapter 现在来看看enqueue传入的参数callback,这个参数可能和很多人心中想的并不一样,它并不是用户在使用时传入的那个Callback对象。那么他是从哪里来的呢?不知道你还记不记得我之前在Retrofit.Builder.build()方法中提到过一句代码Platform.get()。在不使用addCallAdapterFactory的情况下。将会使用Platform的一种内部类,在Android环境下将会使用到Android类(这其实是个策略模式)

static class Android extends Platform {@Override public Executor defaultCallbackExecutor() {return new MainThreadExecutor();}@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {return new ExecutorCallAdapterFactory(callbackExecutor);}static class MainThreadExecutor implements Executor {// Looper.getMainLooper()就是为嘛响应会在主线程的原因private final Handler handler = new Handler(Looper.getMainLooper());@Override public void execute(Runnable r) {handler.post(r);}}
}
复制代码

上面的代码先稍微放一下,我们继续看retrofit.Bulider.build,其中有几句比较关键的代码

callFactory = new OkHttpClient();
callbackExecutor = platform.defaultCallbackExecutor();
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
复制代码

结合Android类中的代码可以看出,其最后生成了ExecutorCallAdapterFactory类。虽然看到了CallAdapter.Factory,但是到底是哪里执行了enqueue方法呢?现在我们来看看retrofit.create的最后一句代码serviceMethod.callAdapter.adapt(okHttpCall) 

Converter

现在回到OkhttpCall.enqueue方法中,在其中还有一句重要的代码没有看,那就是response = parseResponse(rawResponse);,我们来看看这其中做了什么。

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOExceptionResponseBody rawBody = rawResponse.body();// Remove the body's source (the only stateful object) so we can pass thrawResponse = rawResponse.newBuilder().body(new NoContentResponseBody(rawBody.contentType(), rawBody.conte.build();...ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);try {T body = serviceMethod.toResponse(catchingBody);// 解析body,比如Gson解析return Response.success(body, rawResponse);} catch (RuntimeException e) {// If the underlying source threw an exception, propagate that rather // a runtime exception.catchingBody.throwIfCaught();throw e;}
}
### ServiceMethod
R toResponse(ResponseBody body) throws IOException {return responseConverter.convert(body);
}
复制代码

可以看出parseResponse最终调用了Converter.convert方法。这里以常用的GsonConverterFactory为例。

# GsonConverterFactory
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,Retrofit retrofit) {TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));return new GsonResponseBodyConverter<>(gson, adapter);
}
# GsonResponseBodyConverter
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {private final Gson gson;private final TypeAdapter<T> adapter;GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {this.gson = gson;this.adapter = adapter;}@Override public T convert(ResponseBody value) throws IOException {JsonReader jsonReader = gson.newJsonReader(value.charStream());try {return adapter.read(jsonReader);} finally {value.close();}}
}
复制代码

responseBodyConverter方法中用到的type参数就是之前我在CallAdapter中提到的responseType方法的返回值。生成adapter方法,用于convert方法使用。OkHttpCall在这之后的代码就比较简单了,通过回调将转换后得响应数据发送出去即可 本文分析了Retrofit的执行流程,其实包含了Retrofit、ServiceMethod、OkHttpCall、CallAdapter、Converter等方面。Retrofit的代码相对是比较少,也比较容易理解的,不过却是很好的架构实例。

Android技术交流群653583088,欢迎大家加入交流,畅谈!本群有免费学习资料视频’

http://www.jmfq.cn/news/4998385.html

相关文章:

  • 商城网站入驻系统/免费游戏推广平台
  • 宁波做外贸网站/优化网站内容
  • 做彩票网站代理犯法吗/kol推广是什么意思
  • 什么是网络营销网络营销的目的有哪些内容/灯塔网站seo
  • 珠海响应式网站建设费用/国内新闻最新消息今天简短
  • 北京昌平网站建设/百度营销中心
  • iis8.5安装wordpress/百度网站快速优化
  • 福州响应式网站/十大放黄不登录不收费
  • 手机网站布局教程/排名sem优化软件
  • 中小企业网络设计论文/谷歌seo是什么
  • 网站开发与网页设计大作业/石家庄房价
  • 网站推广是做什么工作/推广一个产品有哪些方式
  • 所有网站域名都有/seo百度关键词优化软件
  • 先建网站还是先做app好/超级seo外链工具
  • 网站做文件检查/营销策划方案内容
  • 高端网站开发注意事项/高端企业网站模板
  • 大学网站建设评比考核办法/seo网络营销课程
  • 金阊苏州网站建设/seo技术外包
  • 重庆手机网站建设/搜索引擎有哪些
  • 装修网站实景图vr怎么做的/查询网 网站查询
  • 北京疫情消息最新通报/北京seo优化外包
  • 网站浏览记录怎么做/策划网络营销方案
  • 网站做排名教程/东莞哪种网站推广好
  • 龙岩网站制作公司/郑州网络营销公司哪个好
  • 基于互联网怎样做网站推广/石家庄百度推广排名优化
  • 怎样查看别人网站流量/包就业的培训学校
  • 做ppt找素材的网站/搜狗网页
  • 浙江做网站平台的科技公司/营销培训方案
  • 做网站所需要哪方面的知识/制作网站免费
  • 最好网站建设公司/百度识图搜索图片来源