面對一個項目,對于Android應用開發框架的選擇,我想過三種方案:
1.使用Loader + HttpClient + GreenDao + Gson + Fragment,優點是可定制性強,由于使用Google家自己的Loader和LoaderManager,代碼健壯性強。
缺點是整套代碼學習成本較高,使用過程中樣板代碼較多,(比如每一個Request都需要產生一個新類)
2.Volley,作為Google在IO大會上得瑟過的一個網絡庫,其實不算什么新東西(2013 IO發布),使用較為簡單,請求可以取消,可以提供優先級請求,看起來還是不錯的。
3.Retrofit,一款為了使請求極度簡單化的REST API Client,呼聲也很高,使用門檻幾乎是小白型。
如何選擇呢?首先干掉1,因為對新人的學習成本確實太高,如果要快速開發一個項目,高學習成本是致命的,同時使用起來樣板代碼很多。
那么如何在Volley和Retrofit中選擇呢?盡管網上有很多文章在介紹兩個框架的使用方法,而對于其原理,特別是對比分析較少,如果你手里有一個項目,如何選擇網絡模塊呢?
首先說明一下這兩個網絡框架在項目中的層次:

從上圖可知,不管Volley還是Retrofit,它們都是對現有各種方案進行整合,并提供一個友好,快速開發的方案,在整合過程中,各個模塊都可以自行定制 或者替換。比如反序列化的工作,再比如HttpClient。
而在本文我們將簡略地來看一下Retrofit的源碼部分。
注意,本文并不是使用Retrofit的幫助文檔,建議先看Retrofit的文檔和OkHttp的文檔,這些對于理解余下部分很重要。
使用Retrofit發送一個請求
假設我們要從這個地址 http://www.exm.com/search.json?key=retrofit中獲取如下Json返回:
{ "data": [ { "title":"Retrofit使用簡介", "desc":"Retrofit是一款面向Android和Java的HttpClient", "link":"http://www.exm.com/retrofit" }, { "title":"Retrofit使用簡介", "desc":"Retrofit是一款面向Android和Java的HttpClient", "link":"http://www.exm.com/retrofit" }, { "title":"Retrofit使用簡介", "desc":"Retrofit是一款面向Android和Java的HttpClient", "link":"http://www.exm.com/retrofit" } ] }1.引入依賴
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'//gson解析compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
2.配置Retrofit
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://www.exm.com") .addConverterFactory(GsonConverterFactory.create()) .client(new OkHttpClient()) .build();3.新建Model類 SearchResult來解析結果
4.新建請求接口
Retrofit使用注解來定義一個請求,在方法上面指定請求的方法等信息,在參數中指定參數等信息。
public interface RestApi { @GET("/search.json") Call<List<SearchResult>> search( @Query("key") String key ); //可以定義其它請求 @GET("/something.json") Call<SomeThing> dosomething( @Query("params") long params ....... ....... );}5.發送請求,我們可以發送同步請求(阻塞當前線程)和異步請求,并在回調中處理請求結果。
RestApi restApi = retrofit.create(RestApi.class); Call<List<SearchResult>> searchResultsCall = resetApi.search("retrofit"); //Response<List<SearchResult> searchResults = searchResultsCall.execute(); 同步方法 searchResultsCall.enqueue(new Callback<List<SearchResult>>() { @Override public void onResponse(Response<List<SearchResult>> response, Retrofit retrofit) { content.setText(response.body().toString()); } @Override public void onFailure(Throwable t) { content.setText("error"); } });Retrofit源碼分析
Retrofit整個項目中使用了動態代理和靜態代理,如果你不太清楚代理模式,建議先google一下,如果對于Java的動態代理原理不是太熟悉,強烈建議先看:這篇文章-戲說代理和Java動態代理
ok,下面按照我們使用Retrofit發送請求的步驟來:
RestApi restApi = retrofit.create(RestApi.class); //產生一個RestApi的實例
輸入一個接口,直接輸出一個實例。
這里岔開說一句,現在隨便在百度上搜一下Java動態代理,出來一堆介紹AOP(面向切面編程)和Spring,導致一部分人本末倒置,認為動態代理幾乎等于AOP,甚至有些人認為動態代理是專門在一個函數執行前和執行后添加一個操作,比如統計時間(因為現在幾乎所有介紹動態代理的地方都有這個例子),害人不淺。實際上動態代理是JDK提供的API,并不是由這些上層建筑決定的,它還可以做很多別的事情,Retrofit中對動態代理的使用就是佐證。
摟一眼這里的源碼,再次建議,如果這里代碼看不明白,先看看上面提到的那篇文章:
public <T> T create(final Class<T> service) { //返回一個動態代理類的實例 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, //這個InvocationHandler是關鍵所在,以后調用restapi接口中的方法都會被發送到這里 new InvocationHandler() { private final Platform platform = Platform.get(); @Override public Object invoke(Object proxy, Method method, Object... args) throws Throwable { /* 如果是Object的方法,如toString()等,直接調用InvocationHandler的方法, *注意,這里其實是沒有任何意義的,因為InvocationHandler其實是一個命令傳送者 *在動態代理中,這些方法是沒有任何語義的,所以不需要在意 */ if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } //對于Java8的兼容,在Android中不需要考慮 if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } //返回一個Call對象 return loadMethodHandler(method).invoke(args); } });}我們可以看到Retrofit.create()之后,返回了一個接口的動態代理類的實例,那么我們調用這個代理類的方法時,調用自然就被發送到我們定義的InvocationHandler中,所以調用
Call<List<SearchResult>> searchResultsCall = resetApi.search("retrofit"); 時,直接調用到InvocationHandler的invoke方法,下面是invoke此時的上下文:
@Override public Object invoke(Object proxy, Method method, Object... args) throws Throwable { //proxy對象就是你在外面調用方法的resetApi對象 //method是RestApi中的函數定義, //據此,我們可以獲取定義在函數和參數上的注解,比如@GET和注解中的參數 //args,實際參數,這里傳送的就是字符串"retrofit" //這里必然是return 一個Call對象 return loadMethodHandler(method).invoke(args); }此時,invoke的返回必然是一個Call,Call是Retrofit中對一個Request的抽象,由此,大家應該不難想象到loadMethodHandler(method).invoke(args); 這句代碼應該就是去解析接口中傳進來的注解,并生成一個OkHttpClient中對應的請求,這樣我們調用searchResultsCall時,調用OkHttpClient走網絡即可。確實,Retrofit的主旋律的確就是這樣滴。
注意,實際上Call,CallBack這種描述方式是在OkHttp中引入的,Retrofit底層使用OkHttp所以也是使用這兩個類名來抽象一個網絡請求和一個請求回來之后的回調。總體來看,Retrofit中的Call Callback持有一個OkHttp的Call Callback,將對Retrofit中的各種調用轉發到OkHttp的類庫中,實際上這里就是靜態代理啦,因為我們會定義各種代理類,比如OkHttpCall
注 下文中如不無明確支出,則所有的Call,CallBack都是Retrofit中的類
MethodHandler類
MethodHandler類,它是Retrofit中最重要的抽象了,每一個MethodHandler對應于本例的RestApi中的一個每個方法代表的請求以及和這個請求相關其它配置,我們來看看吧。
//這個OkHttp的工廠,用于產生一個OkHttp類庫中的Call,實際上就是傳入配置的Builder的OkHttpClientprivate final okhttp3.Call.Factory callFactory;//通過Method中的注解和傳入的參數,組建一個OkHttp的Requestprivate final RequestFactory requestFactory;//用于對Retrofit中的Call進行代理private final CallAdapter<?> callAdapter;//用于反序列化返回結果private final Converter<ResponseBody, ?> responseConverter;// 返回一個Call對象Object invoke(Object... args) { return callAdapter.adapt(new OkHttpCall<>(callFactory, requestFactory, args, responseConverter));}在Retrofit中通過添加Converter.Factory來為Retrofit添加請求和響應的數據編碼和解析。所以我們可以添加多個Converter.Factory為Retrofit提供處理不同數據的功能。
CallAdapter 可以對執行的Call進行代理,這里是靜態代理。我們也可以通過添加自己的CallAdapter來作一些操作,比如為請求加上緩存:
new CallAdapter.Factory { @Override public <R> Call<R> adapt(Call<R> call) { return call;} }class CacheCall implements Call { Call delegate; CacheCall(Call call) { this.delegate = call; } @Override public void enqueue(Callback<T> callback) { //查看是否有緩存,否則直接走網絡 if(cached) { return cache; } this.delegate.enqueue(callback); }}至此,我們在調用resetApi.search("retrofit");時,實際上調用的層層代理之后的OkHttpCall,它是MethodHandler中invoke的時候塞入的。看看OkHttpCall中的代碼吧:
@Override public void enqueue(final Callback<T> callback) { okhttp3.Call rawCall; try { //創建一個okhttp的Call rawCall = createRawCall(); } catch (Throwable t) { callback.onFailure(t); return; } //直接調用okhttp的入隊操作rawCall.enqueue(new okhttp3.Callback() { private void callFailure(Throwable e) { try { callback.onFailure(e); } catch (Throwable t) { t.printStackTrace(); } } private void callSuccess(Response<T> response) { try { callback.onResponse(response); } catch (Throwable t) { t.printStackTrace(); } } @Override public void onFailure(Request request, IOException e) { callFailure(e); } @Override public void onResponse(okhttp3.Response rawResponse) { Response<T> response; try { //解析結果 response = parseResponse(rawResponse); } catch (Throwable e) { callFailure(e); return; } callSuccess(response); }});}如此一來,OkHttpClient的回調也被引導到我們的Callback上來,整個流程就已經走通了。
總結
終于到了總結的時候了,一般來說,這都是干貨的時候,哈哈~
Volley對比優勢
1.緩存處理;Volley自己就提供了一套完整的緩存處理方案,默認使用文件存儲到磁盤中,并且提供了TTL SOFTTTL這么體貼入微的機制;一個Request可能存在兩個Response,對于需要顯示緩存,再顯示網絡數據的場景真是爽的不要不要的。而Retrofit中并沒有提供任何和緩存相關的方案。
2.代碼簡單,可讀性高。Volley的代碼是寫的如此的直接了當,讓你看起代碼來都不需要喝口茶,這樣的好處是我們我們需要修改代碼時不太容易引入bug....
主站蜘蛛池模板:
长葛市|
澳门|
资中县|
渭南市|
邓州市|
绵竹市|
客服|
河东区|
托克托县|
潍坊市|
葫芦岛市|
肇源县|
大田县|
宁安市|
沧源|
紫阳县|
武穴市|
沽源县|
温泉县|
苏州市|
泸定县|
宣武区|
搜索|
平泉县|
司法|
阳西县|
蓝山县|
修武县|
远安县|
濮阳市|
永城市|
灌南县|
若尔盖县|
郴州市|
淄博市|
屏东市|
乾安县|
寻乌县|
广昌县|
渑池县|
北宁市|