Android開源框架Afinal第一篇——揭開聖女的面紗

Afinal

這是Afinal在github的地址:https://github.com/yangfuhai/afinal

Afinal這個框架主要分4塊:

1、FinalDB模塊:android中的orm框架,一行代碼就可以進行增刪改查。支持一對多,多對一等查詢。

2、FinalActivity模塊:android中的ioc框架,完全註解方式就可以進行UI綁定和事件綁定。無需findViewById和setClickListener等。

3、FinalHttp模塊:通過httpclient進行封裝http數據請求,支持ajax方式加載。

4、FinalBitmap模塊:通過FinalBitmap,imageview加載bitmap的時候無需考慮bitmap加載過程中出現的oom和android容器快速滑動時候出現的圖片錯位等現象。FinalBitmap可以配置線程加載線程數量,緩存大小,緩存路徑,加載顯示動畫等。FinalBitmap的內存管理使用lru算法,沒有使用弱引用(android2.3以後google已經不建議使用弱引用,android2.3後強行回收軟引用和弱引用,詳情查看android官方文檔),更好的管理bitmap內存。FinalBitmap可以自定義下載器,用來擴展其他協議顯示網絡圖片,比如ftp等。同時可以自定義bitmap顯示器,在imageview顯示圖片的時候播放動畫等(默認是漸變動畫顯示)。

 

這裏我們先講FinalHttp模塊,這是它的用法:

複製代碼
AjaxParams params = new AjaxParams(); params.put("username", "michael yang"); params.put("password", "123456"); params.put("email", "[email protected]"); params.put("profile_picture", new File("/mnt/sdcard/pic.jpg")); // 上傳文件params.put("profile_picture2", inputStream); // 上傳數據流 params.put("profile_picture3", newByteArrayInputStream(bytes)); // 提交字節流 FinalHttp fh new FinalHttp(); fh.post("http://www.yangfuhai.com", params,new AjaxCallBack(){ @Override public void onLoading(long count, long current) { textView.setText(current+"/"+count); } @Override public void onSuccess(String t) { textView.setText(t==null?"null":t); } });
複製代碼

大家看到了吧,fh.get(baseUrl, params, new AjaxCallBack(){});

這句話的底層就是HttpClient執行HttpGet或者HttpPost請求的一個封裝,其中baseUrl+params拼湊起來就是url,而後面的AjaxCallBack就是對HttpClient對http請求得到的一個HttpResponse響應結果的分析回調。

我們來看具體的流程步驟:

第一步:初始化FinalHttp,然後執行get()方法

public void get( String url, AjaxParams params, AjaxCallBack<? extends Object> callBack) { sendRequest(httpClient, httpContext, new HttpGet(getUrlWithQueryString(url, params)), null, callBack); }

第二步:我們看sendRequest()這個方法,這個方法就是把get方法裏的參數傳遞到這個函數,然後發起http請求。

複製代碼
protected <T> void sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, AjaxCallBack<T> ajaxCallBack) { if(contentType != null) { uriRequest.addHeader("Content-Type", contentType); } new HttpHandler<T>(client, httpContext, ajaxCallBack,charset) .executeOnExecutor(executor, uriRequest); }
複製代碼

這是一個保護級的方法,其實還是一個馬甲,正真執行的還是那個HttpHandler裏的exe方法。我們看到這個方法的參數有DefaultHttpClient,這個都不用說了大家都很熟悉,HttpContext就是一個上下文,HttpUriRequest就是一個get,put,delete,post等http請求,然後就是添加頭部信息,比如要不要進行壓縮,這裏貌似用了zip壓縮使得傳輸速率更快,再後面就是回調函數接口,判斷請求是否成功失敗等。

第三步:進入HttpHandler類,這是一個處理http請求的類。這個類是繼承AsyncTask,但是這個AsyncTask類並不是原生的,而是經過作者精心修改的。沒有深入去看AsyncTask,大略看了一下,貌似doInBackground這個方法是放進一個線程池裏去執行的。這個線程池配置的很精細,就像批量加載圖片那個例子,可以只想你個完上一個線程,就馬上執行下一個任務。

1.這個類還實現了EntityCallBack回調接口,並且接收了AjaxCallBack這個回調實例。我們先看doInBackground方法。

複製代碼
protected Object doInBackground(Object... params) { if(params!=null && params.length == 3){ targetUrl = String.valueOf(params[1]); isResume = (Boolean) params[2]; } try { publishProgress(UPDATE_START); // 開始makeRequestWithRetries((HttpUriRequest)params[0]); } catch (IOException e) { publishProgress(UPDATE_FAILURE,e,e.getMessage()); // 結束 } return null; }
複製代碼

2.可以看到真正執行的方法是makeRequestWithRetries(HttpUriRequest *)方法,進去看看先

複製代碼
private void makeRequestWithRetries(HttpUriRequest request) throws IOException { if(isResume && targetUrl!= null){ File downloadFile new File(targetUrl); long fileLen = 0if(downloadFile.isFile() && downloadFile.exists()){ fileLen =downloadFile.length(); } if(fileLen > 0) request.setHeader("RANGE", "bytes="+fileLen+"-"); } boolean retry = true; IOException cause null; HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler(); while (retry) {try { if (!isCancelled()) { HttpResponse response = client.execute(request, context); if (!isCancelled()) { handleResponse(response); } } return; } catch (UnknownHostException e) { publishProgress(UPDATE_FAILURE, e,"unknownHostException:can't resolve host"); return; } catch (IOException e) { cause = e; retry = retryHandler.retryRequest(cause, ++executionCount,context); } catch (NullPointerException e) { // HttpClient 4.0.x 之前的一個bug // http://code.google.com/p/android/issues/detail?id=5255 cause = new IOException("NPE in HttpClient" +e.getMessage()); retry = retryHandler.retryRequest(cause, ++executionCount,context); }catch (Exception e) { cause newIOException("Exception" + e.getMessage()); retry = retryHandler.retryRequest(cause, ++executionCount,context); } }if(cause!=nullthrow cause; else throw new IOException("未知網絡錯誤"); }
複製代碼

其中isResume是斷點續傳標誌,targetUrl判斷是文件的話就添加文件大小頭部信息。retry是遇到錯誤是否要重試標誌,FinalHttp有這個參數配置,可以設置重試次數。然後就是HttpClient執行Http請求獲取響應的操作,如果這個過程中UI上的交互有取消操作的話。可以通過isCancelled()這個方法得知從而取消請求。如果請求順利會得到一個HttpResponse,而處理這個響應結果是handleResponse()方法。

3.這是專門處理響應結果的方法

複製代碼
private void handleResponse(HttpResponse response) { StatusLine status = response.getStatusLine(); if(status.getStatusCode() >= 300) { String errorMsg = "response status error code:"+status.getStatusCode();if(status.getStatusCode() == 416 && isResume){ errorMsg += " \n maybe you have download complete."; } publishProgress(UPDATE_FAILURE,new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()),errorMsg); }else { try { HttpEntity entity = response.getEntity(); Object responseBody nullif (entity != null) { time =SystemClock.uptimeMillis(); if(targetUrl!=null){ responseBody = mFileEntityHandler.handleEntity(entity,this,targetUrl,isResume); } else{ responseBody = mStrEntityHandler.handleEntity(entity,this,charset); } } publishProgress(UPDATE_SUCCESS,responseBody); } catch(IOException e) { publishProgress(UPDATE_FAILURE,e,e.getMessage()); } } }
複製代碼

通過狀態碼,判斷成功後處理得到的HttpEntity。如果這個response是字符串就由StringEntityHandler這個類去解析,如果是文件就是FileEntityHandler解析。得到結果後,就是publishProgress去推送了,這個方法在前面的方法中都看到有被調用。稍微對AsyncTask熟悉的人就知道這個方法將可以觸發onProgressUpdate(* value).這個方法就是告訴你執行的進度,AfinalHttp中AjaxCallback中的onSuccess,onFailure等方法就是根據這個來觸發的。

   private final static int UPDATE_START = 1private final static int UPDATE_LOADING = 2private final static intUPDATE_FAILURE = 3private final static int UPDATE_SUCCESS = 4;

到這裏這個過程就完成了。

看到這麼多的處理,會覺得這樣是不是會更慢。一個網絡請求處理的極其複雜,想FinalHttp很多默認的配置和繁雜的處理響應並通知處理進程,其實這樣多多少少拖慢了請求的速度。在實際應用尤其感受深切,一遇到網絡慢,跨地域幅度大等教爲惡劣的網絡環境,AFinal就有點顯得捉襟見肘了。

由於篇幅限制,這次就講這麼多了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章