多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > Retrofic 源碼閱讀

Retrofic 源碼閱讀

來源:程序員人生   發布時間:2016-07-22 08:42:58 閱讀次數:2979次

Retrofic 源碼瀏覽

標簽(空格分隔): 源碼瀏覽

1.初識注解

  • 1.1 注解定義
    我們定義過很多接口,但在接口interface前面添加了@是甚么意思了?例如:
public @interface Get { String value() default "" ; }
  • 1.2 注解列表
    這就是注解,那末現在這個我們可以用了嗎?
    答案是不是定的,還不可以用,我們必須申明這個注解用在甚么地方的才可以。
    像下面才可使用:
@Target(METHOD ) @Retention(RUNTIME ) public @interface Get { String value() default "" ; }

我們簡單解釋1下這個注解的意思,這個注解表示注解用于在方法上,在運行時可見,如果要用到參數上,像下面:

@Target(PARAMETER ) @Retention(RUNTIME ) public @interface Path { String value() default "" ; }

更多就請看這個類了

java.lang.annotation.ElementType

2 初識反射

  • newProxyInstance
    在JDK的api里面有1個很重要的反射方法:
/** * Returns an instance of the dynamically built class for the specified * interfaces. Method invocations on the returned instance are forwarded to * the specified invocation handler. The interfaces must be visible from the * supplied class loader; no duplicates are permitted. All non-public * interfaces must be defined in the same package. * * @param loader * the class loader that will define the proxy class * @param interfaces * an array of {@code Class} objects, each one identifying an * interface that will be implemented by the returned proxy * object * @param invocationHandler * the invocation handler that handles the dispatched method * invocations * @return a new proxy object that delegates to the handler {@code h} * @throws IllegalArgumentException * if any of the interface restrictions are violated * @throws NullPointerException * if the interfaces or any of its elements are null */ public static Object newProxyInstance (ClassLoader loader , Class<?>[] interfaces, InvocationHandler h)

我們看這個方法上面的注釋
返回指定接口的動態生成類的實例。在返回的實例方法調用被轉發到InvocationHandler上面。必須從所提供的類裝載器可見接口;不允許任何重復。所有非公共接口必須在同1個包中定義。
也許還是沒有看懂,說白了就是通過給定的接口生成1個對應的實例,這個接口的方法在實例中實現的時候被反過來調用InvocationHandler上
- InvocationHandler
所以我們需要去實現InvocationHandler類

new InvocationHandler() { @Override public Object invoke(Object proxy , Method method, Object[] args ) throws Throwable { return null; } }

很明顯,你只要調用這個接口的方法,都會被反過來調用上面這個方法,
我們來看這個方法的參數
Object proxy
Method method 這個是接口方法的1些描寫,里面包括對方法的各種描寫。
Object[] args 就是你調用這個方式時,實際的參數。

3.通過接口反射出實例

所以整合起來,寫個例子:

@Documented @Target(METHOD ) @Retention(RUNTIME ) public @interface Get { String value() default "" ; } @Documented @Target(PARAMETER ) @Retention(RUNTIME ) public @interface Path { String value() default "" ; } public interface IIterface { @Get(value="testPath" ) String testMethod( @Path ("path" )String path); } public static void main(String[] args) { IIterface test = (IIterface) Proxy.newProxyInstance(IIterface.class.getClassLoader(), new Class[] { IIterface.class }, new InvocationHandler() { @Override public Object invoke(Object proxy , Method method, Object[] args ) throws Throwable { StringBuilder sb = new StringBuilder(); method.getReturnType();// return type. Annotation[][] anss = method.getParameterAnnotations(); String pathValue = "" ; out: for (Annotation[] ans : anss) { for (Annotation an : ans) { if(an instanceof Path){ Path path = (Path)an ; pathValue = path.value(); break out; } } } Get get = method.getAnnotation(Get .class); String value = get .value(); sb.append( value).append("/" ); sb.append( pathValue).append("/" ); sb.append( args[0]); return sb .toString(); } }); String result = test .testMethod("code_path"); System. out.println(result ); }

通過這個例子,應當可以完成理解注解的使用了吧。
如果想下載完成demo

4. Retrofit2

通過上面的demo我們來看Retrofit2的代碼就簡單了。

4.1 何使用Retrofic2

我們在使用的時候不是先需要定義1個接口嗎?
如:

public interface FusionApi { @GET("/fusion/settings/v1/users/{userId}/applications") Observable<List<CloudState>> applicationsRx(@Path("userId") String userId); }

我們創建對應的實例:

public FusionApi createFusionApi(){ Retrofit.Builder builder = new Retrofit.Builder(); builder.baseUrl(base_url); builder.addConverterFactory(GsonConverterFactory.create()); builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create()); return builder.build().create(FusionApi.class); }

然后我們在使用的時候:

@Test public void applicationsRx() throws Exception { FusionService.getFusionService().setClientInfo(clientInfo); Observable<List<CloudState>> call = FusionService.getFusionService().setClientInfo(clientInfo).createFusionApi().applicationsRx(userId); call.subscribe(new Action1<List<CloudState>>() { @Override public void call(List<CloudState> cloudStates) { System.out.println(cloudStates); } }); }

固然這里使用了Observable了,下1篇我將會使用RxJava和Reconfic2的整合。
其實你看了這篇基本上都已全部使用到了,唯1少了點Observable的使用。
扯遠來,回到我們的話題。

4.2 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 serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } });

1行1行代碼的來解釋下:
第2行: 主要檢測傳入進來的參數是不是為interface接口
第3⑸行: 主要驗證這service的方法

4.3 分析Platform.get()

接下來就是我們前面看到 需要重點分析的代碼:

private final Platform platform = Platform.get();

這1行,由于Recofict2支持3個平臺,android ios java8 所以在這里選擇平太,很明顯我們是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 { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } } }

其實看這個方法很容易理解,1個就是先了1個線程池來履行,1個主線成應當運行的的地方。想必Android入門了,就很容易理解。

4.4 分析ServiceMethod

接下來看

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

很明顯前面2個if都不成立,所以我們直接來看

ServiceMethod serviceMethod = loadServiceMethod(method);

下面我們來看看 這個loadServiceMethod方法做了甚么?

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

這個方法其實沒干甚么,就是把method封裝成ServiceMethod,做了1下緩存,如果有直接取,沒有就重新封裝1次,我們看看這個封裝的方法:

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

第1個參數先不講授,第2個參數先從里面讀取這個方法所有的注解。
this.methodAnnotations=method.getAnnotations(); 這個是讀取象Get這樣1類的注解
this.parameterTypes=method.getGenericParameterTypes(); 這個讀取方法的參數類型
this.parameterAnnotationsArray=method.getParameterAnnotations(); 這個讀取參數里面的注解。

我們再看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); }

先不看retrofit這個的使用,這個后面講授:

for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(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); } else if (annotation instanceof HEAD) { parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false); if (!Void.class.equals(responseType)) { throw methodError("HEAD method must use Void as response type."); } } else if (annotation instanceof PATCH) { parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true); } else if (annotation instanceof POST) { parseHttpMethodAndPath("POST", ((POST) annotation).value(), true); } else if (annotation instanceof PUT) { parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true); } else if (annotation instanceof OPTIONS) { parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false); } else if (annotation instanceof HTTP) { HTTP http = (HTTP) annotation; parseHttpMethodAndPath(http.method(), http.path(), http.hasBody()); } else if (annotation instanceof retrofit2.http.Headers) { String[] headersToParse = ((retrofit2.http.Headers) annotation).value(); if (headersToParse.length == 0) { throw methodError("@Headers annotation is empty."); } headers = parseHeaders(headersToParse); } else if (annotation instanceof Multipart) { if (isFormEncoded) { throw methodError("Only one encoding annotation is allowed."); } isMultipart = true; } else if (annotation instanceof FormUrlEncoded) { if (isMultipart) { throw methodError("Only one encoding annotation is allowed."); } isFormEncoded = true; } }

其實很簡單,就是對這個注解1個1個進行判斷,是不是是我們已定義的注解類型。然后做了檢查而已,然后標注哪些注解將被用到。
我們讀其中1個注解的解析:

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; if (value.isEmpty()) { return; } // Get the relative URL path and existing query string, if present. int question = value.indexOf('?'); if (question != -1 && question < value.length() - 1) { // Ensure the query string does not have any named parameters. String queryParams = value.substring(question + 1); Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams); if (queryParamMatcher.find()) { throw methodError("URL query string \"%s\" must not have replace block. " + "For dynamic query parameters use @Query.", queryParams); } } this.relativeUrl = value; this.relativeUrlParamNames = parsePathParameters(value); }

這個方法是讀取里面的具體參數的值,然后存入到relativeUrl,relativeUrlParamNames 這里面,

static Set<String> parsePathParameters(String path) { Matcher m = PARAM_URL_REGEX.matcher(path); Set<String> patterns = new LinkedHashSet<>(); while (m.find()) { patterns.add(m.group(1)); } return patterns; }

然后我們回到開始:

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

這句代碼,我們上面已解釋了ServiceMethod這個里面有啥了。
args 是這個方法傳入具體的參數值
然后看這句:

public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null, returnType, annotations); } public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { int start = adapterFactories.indexOf(skipPast) + 1; for (int i = start, count = adapterFactories.size(); i < count; i++) { CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } }

從這里就是取出adapter
那我們看看這adapter里面存的是甚么,然后有得到的是甚么樣的callAdapter
搜素源碼能看到 就是我們構造build的時候,使用這個方法添加進去的
addCallAdapterFactory我這里是 用的RxJava
固然沒有添加的話,使用的是系統默許的。至于甚么時候選擇哪一個,你看上面的方法就知道了,通過注解和返回類型匹配的話,就選擇哪一個,如果我們返回的不是Observer類型,那我們應當是Reforcit默許的,我們看看默許的是啥?

CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) { if (callbackExecutor != null) { return new ExecutorCallAdapterFactory(callbackExecutor); } return DefaultCallAdapterFactory.INSTANCE; }

通過判斷,我們沒有實例callbackExecutor,應當是
所以應當是這個:

final class DefaultCallAdapterFactory extends CallAdapter.Factory {

既然找到他的實例了,我們來看看adapt 方法:

@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<Call<?>>() { @Override public Type responseType() { return responseType; } @Override public <R> Call<R> adapt(Call<R> call) { return call; } }; }

事實也是如此。
我們傳入的參數 是OkHttpCall

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

所以返回的是OkHttpCall ,是否是感覺轉了1圈,回到出發點,啥也沒干嘛?
如果那樣理解那就錯了。
在這里,你外面不是使用的是Call的返回參數,所以這個時候,你調用
call.execute().body(); 就得到最后的答案了嗎?
所以我們跟進這個OkHttpCall來看下。

@Override public Response<T> execute() throws IOException { okhttp3.Call call; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; if (creationFailure != null) { if (creationFailure instanceof IOException) { throw (IOException) creationFailure; } else { throw (RuntimeException) creationFailure; } } call = rawCall; if (call == null) { try { call = rawCall = createRawCall(); } catch (IOException | RuntimeException e) { creationFailure = e; throw e; } } } if (canceled) { call.cancel(); } return parseResponse(call.execute()); }

看上面的代碼,重要的是2行代碼,
1行是:call = rawCall = createRawCall();
那我們先看看這個方法:
createRawCall

private okhttp3.Call createRawCall() throws IOException { Request request = serviceMethod.toRequest(args); okhttp3.Call call = serviceMethod.callFactory.newCall(request); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; }

第1行:我們看方法:

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(); } Request build() { HttpUrl url; HttpUrl.Builder urlBuilder = this.urlBuilder; if (urlBuilder != null) { url = urlBuilder.build(); } else { // No query parameters triggered builder creation, just combine the relative URL and base URL. url = baseUrl.resolve(relativeUrl); if (url == null) { throw new IllegalArgumentException( "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl); } } RequestBody body = this.body; if (body == null) { // Try to pull from one of the builders. if (formBuilder != null) { body = formBuilder.build(); } else if (multipartBuilder != null) { body = multipartBuilder.build(); } else if (hasBody) { // Body is absent, make an empty body. body = RequestBody.create(null, new byte[0]); } } MediaType contentType = this.contentType; if (contentType != null) { if (body != null) { body = new ContentTypeOverridingRequestBody(body, contentType); } else { requestBuilder.addHeader("Content-Type", contentType.toString()); } } return requestBuilder .url(url) .method(method, body) .build();

是在這里根據參數,注解,構造了1個http要求嗎?這里面就有了全部http要求的消息了。

回到原來的那個地方,我們分析第2個,如果對okhttp比較熟習的話,這就可以直接看懂了,但是我還是1直分析下去。

前面1行代碼分析完了,我們來分析第2處:

parseResponse(call.execute());

call.execute(),就是根據上面全部http要求,得到了http的返回,然后再進行分析,我們來看分析的代碼:

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); // Remove the body's source (the only stateful object) so we can pass the response along. rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) .build(); int code = rawResponse.code(); if (code < 200 || code >= 300) { try { // Buffer the entire body to avoid future I/O. ResponseBody bufferedBody = Utils.buffer(rawBody); return Response.error(bufferedBody, rawResponse); } finally { rawBody.close(); } } if (code == 204 || code == 205) { return Response.success(null, rawResponse); } ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { T body = serviceMethod.toResponse(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { // If the underlying source threw an exception, propagate that rather than indicating it was // a runtime exception. catchingBody.throwIfCaught(); throw e; } }

如果要求時成功的,則我們只需要看著兩行代碼:

T body = serviceMethod.toResponse(catchingBody); return Response.success(body, rawResponse);

跟入到這行代碼

T toResponse(ResponseBody body) throws IOException { return responseConverter.convert(body); }

1看就知道,經過1個Converter,轉換到我們想要的類型了。所以body就是我們要的封裝結果。
然后以封裝最后的數據類型傳回了我們最初的調用端。

這里走分析源碼已走了1圈了。

文章寫的亂,第1次寫,可能思路寫的不是很清晰,后續可以需要修改。

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 久草成人在线 | 一本大道香蕉久在线不卡视频 | 在线播放人成午夜免费视频 | 国产五区 | 欧美videosfree性喷潮 | 欧美一级毛片欧美一级无片 | 网友自拍区一区二区三区 | 国产h视频在线观看 | jizzjlzz大学生 | 亚洲春色综合另类网蜜桃 | 亚洲第一网站在线观看 | 国产成人综合亚洲欧美在 | 黄色wwwcom | 武则天一级淫片免费放 | 国产精品自拍一区 | 男人天堂999 | 亚洲天天网综合自拍图片专区 | xxx在线视频| 羞羞动漫在线免费观看 | 精品h视频| 在线欧美一级毛片免费观看 | 久久国产精品久久国产精品 | 国产毛片片精品天天看视频 | 精品久久久久久国产免费了 | 久久国 | 99热这里只精品99re66 | 欧美精品v国产精品v | 久操网在线 | 高清免费国产在线观看 | 国产h视频在线观看免费 | 羞羞动漫网址 | 免费高清黄色 | 亚洲一本之道在线观看不卡 | 亚洲成人在线免费视频 | 国产精品香蕉在线观看不卡 | 欧美成人精品第一区 | 久草福利在线播放 | 欧美精欧美乱码一二三四区 | aⅴ一区二区三区无卡无码 aⅴ在线免费观看 | 成人午夜影视全部免费看 | 国产午夜毛片v一区二区三区 |