編輯:關於Android編程
上一篇講解了retrofit2的簡單用法,這一邊主要解析一下reftofit2的原理,就從Retrofit的create(final Class
我們先來看看create()這個方法裡干了些什麼:
public當看到proxy是不是有點眼熟呢,沒錯就是動態代理,主要使用newProxyInstance()方法來返回一個類的代理實例,它的參數需要傳遞一個類的加載器,類本身,以及InvocationHandler的子類對象,這裡它使用的是匿名內部類。主要動作都是在InvocationHandler中進行的,它裡面只有一個invoke()方法,每當我們調用代理類裡面的方法時,invoke()方法都會被執行,我們可以從參數中獲得很多信息,method的方法名,從args中獲取到方法的參數等。T create(final Class 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); } }); }
invoke()方法裡主要做的就是:
首先,將method轉換為serviceMethod;
然後,通過serviceMethod,arg獲取到okHttpCall對象;
最後,通過serviceMethod.callAdapter.adapt()對okHttpCall進行封裝返回call對象。
下面一步步來分析。
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; }
public Builder(Retrofit retrofit, Method method) { this.retrofit = retrofit; this.method = method; this.methodAnnotations = method.getAnnotations(); this.parameterTypes = method.getGenericParameterTypes(); this.parameterAnnotationsArray = method.getParameterAnnotations(); }
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(); ... return new ServiceMethod<>(this); }首先在builder的構造方法裡初始化一些參數,然後再build()方法裡通過new ServiceMethod(),並將這個對象返回來獲得servicMethod對象,下面來仔細看看build()方法:
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); } }這個方法裡最主要就是獲取到method的類型和注解,然後調用了retrofit的callAdapter()方法,
public CallAdapter callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null, returnType, annotations); }而retrofit的callAdapter()方法調用的是自己的nextCallAdapter()方法:
public CallAdapter nextCallAdapter(CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { checkNotNull(returnType, "returnType == null"); checkNotNull(annotations, "annotations == null"); 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; } }
public static final classBuilder { ... publicBuilderaddCallAdapterFactory(CallAdapter.Factory factory) { adapterFactories.add(checkNotNull(factory, "factory == null")); return this; } ... public Retrofitbuild() { List上面的代碼中我們可以看到,不管我們有沒有往adapterFactories中添加元素,adapterFactories集合中都至少會有一個ExcutorCallAdapterFactory對象,也就是說上面通過createCallAdapter()方法得到的callAdapter就是ExcutorCallAdapterFactory,這個在後面很關鍵。adapterFactories = newArrayList<>(this.adapterFactories); adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); ... } } CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) { if(callbackExecutor != null) { return new ExecutorCallAdapterFactory(callbackExecutor); } return DefaultCallAdapterFactory.INSTANCE; }
這個的過程和構造callAdapter對象基本一致,這裡不再贅述。
OkHttpCall(ServiceMethod這一步比較簡單,就是傳遞參數serviceMethod, Object[] args) { this.serviceMethod = serviceMethod; this.args = args; }
就這麼一句,這是嘛呀,但是經過第一步的分析,我們已知道serviceMethod.callAdapter就是ExecutorCallAdapterFactory,那麼我們可以看看在ExecutorCallAdapterFactory類中有沒有發現CallAdapter的另類應用呢,一看,果不其然在重寫父類的get()方法中我們找到了答案:T adapt(Call call);
@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 >() { @Override public Type responseType() {return responseType; } @Override public Call adapt(Call call) {return new ExecutorCallbackCall<>(callbackExecutor, call); } }; }
當看到return new CallAdapter中的adapt(Call call)我們就完全知其所以然了,至於ExecutorCallbackCall怎麼應用的我們在發起網絡請求的時候講解。
ok,當我們得到接口的代理實例之後,通過代理接口調用裡面的方法,就會觸發InvocationHandler對象中的invoke方法,從而完成上面的三個步驟並且返回一個Call對象,通過Call對象就可以去完成我們的請求了,Retrofit為我們提供兩種請求方式,一種是同步,一種是異步。我們這裡就以異步方式來講解:
當我們通過retrofit的create()方法獲得call對象,再調用call.enque()去訪問網絡時,方法中有回掉函數,回掉函數裡重寫兩個方法,一個成功,一個失敗,來看下怎麼回事,這個call對象其實就是ExcutorCallAdapterFactory,來看裡面具體實現:public static final classExecutorCallbackCallimplementsCall { finalExecutorcallbackExecutor; finalCall delegate; ExecutorCallbackCall(Executor callbackExecutor, Call delegate) { this.callbackExecutor = callbackExecutor; this.delegate = delegate; } @Overridepublicvoidenqueue(final Callback callback) { if(callback == null)thrownewNullPointerException("callback == null"); delegate.enqueue(new Callback () { @Override public void onResponse(Call call, final Response response) { callbackExecutor.execute(new Runnable() { @Override public void run() { if (delegate.isCanceled()) { callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled")); } else { callback.onResponse(ExecutorCallbackCall.this, response); } } }); } @Override public void onFailure(Call call, final Throwable t) { callbackExecutor.execute(new Runnable() { @Override public void run() { callback.onFailure(ExecutorCallbackCall.this, t); } }); } }); }
ExecutorCallbackCall(Executor callbackExecutor, Calldelegate) { this.callbackExecutor = callbackExecutor; this.delegate = delegate; }
@Override public void enqueue(final Callbackcallback) { if (callback == null) throw new NullPointerException("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(); } 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 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 response) { try { callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { t.printStackTrace(); } } }); }
著手開發一款應用的時候,設置或者菜單頁面是可能需要的,但是,那重復的布局會很令人苦惱。新手可能會一項項的重復繪制,有經驗的你或許會用到include,或者用到組合控件。除
前言:關於使用ViewPageIndicator和ViewPager實現Tab導航,在開發社區裡已經有一堆的博客對其進行了介紹,如果我還在這裡寫如何去實現,那簡直就是老生
1.介紹Runtime Permissions官方說明Android 6.0之前,權限在應用安裝過程中只詢問一次,以列表的形式展現給用戶,然而大多數用戶並不會注意到這些,
本文實例講述了Android開發實現TextView顯示豐富的文本的方法。分享給大家供大家參考,具體如下:如圖,顯示html的元素控件,點擊連接實現上網,發email,撥