PS:看完了LGD的六場比賽...讓人心酸...
學習內容:
1.Http請求的過程...
2.Volley的簡單介紹...
1.Http請求...
這里只是簡單的說一下Http請求的過程...非常的簡單...首先是發送Request..然后服務器在獲取到Request請求后會對其進行相應的處理,然后以Response的形式進行返回,然后分配Response,即誰發送的請求,那么響應就分配給誰...
2.Volley簡單介紹...
這里只是先簡單的說一下Volley,Volley框架是由Google發布的一款開源框架...這個框架主要是針對網絡請求而包裝生成的開源框架...主要功能是異步的網絡請求和圖片的加載,適用於Android這種請求頻繁而每次請求數據量並不是很大的這一類網絡請求...通過源碼能夠發現Volley有非常好的擴展性,更多的地方采用接口的設計...所以我們都可以自己重寫內部的一些方法...總體的設計思路也是非常的明確的...
客戶端如果想通過網絡連接來連接服務器,那么首先需要發送相關請求...每一個請求都需要被建立,那么建立請求的類就靠Request.java來實現...
Request.java(源碼解析)
簡單的說說Request.java,這是Volley的最核心的類,Request.java不僅僅封裝了Request請求,還包括對服務器返回的Response的數據信息進行相應的處理..總之Request.java是一個最大的父類,內部封裝了非常多的方法...其他的幾個子類都是通過繼承Request.java從而實現自己的功能...Request只是對外提供了一個接口,任何方式的請求只需要實現接口就能夠實例化自己的請求對象,創建自己內部的方法..從而形成一種良好的擴展...
凡是繼承了Request.java必須要實現的一個方法...
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
這個方法是對網絡服務器響應的一個解析過程..也是最后由這個函數通過postResponse方法,將Response傳遞給ResponseDelivery從而對響應進行分發,不難理解,在每一個Request中實現這個方法,那么也就能夠知道是誰發出的請求,這樣在分發響應的時候也就不會產生錯誤...
2.1 public void addMarker(String tag){}函數...
public void addMarker(String tag) { if (MarkerLog.ENABLED) { mEventLog.add(tag, Thread.currentThread().getId()); } else if (mRequestBirthTime == 0) { mRequestBirthTime = SystemClock.elapsedRealtime(); } }
addMarker函數,其實是就是一個標志,這個函數可以為每一個request添加相應事件標識符,這樣我們就可以通過捕獲標識符的方式從而對每一個request做進一步的操作.
比如說一個網絡請求從請求隊列取出的標識:request.addMarker("network-queue-take");
一個請求被取消的標識:request.addMarker("network-discard-cancelled");
在Volley中很容易看到這些標識,他們的存在就是為了捕獲每一個請求的發生狀態,通過捕獲這些狀態,比如說一個請求已經完成,那么我們捕獲到了請求完成之后,我們就需要將這次請求從請求隊列當中移除,那么這個操作的執行就需要首先捕獲到請求的狀態,我們才能夠采取下一步的操作...總之就是通過標識才能夠清楚的了解請求到底執行到了何種狀態...
2.2 以下幾個函數完成實體部分(Body)中驗證參數的傳遞以及編碼過程...
2.2.1 public byte[] getPostBody() throws AuthFailureError{}
public byte[] getBody() throws AuthFailureError{}
public byte[] getPostBody() throws AuthFailureError { // Note: For compatibility with legacy clients of volley, this implementation must remain // here instead of simply calling the getBody() function because this function must // call getPostParams() and getPostParamsEncoding() since legacy clients would have // overridden these two member functions for POST requests. Map<String, String> postParams = getPostParams(); if (postParams != null && postParams.size() > 0) { return encodeParameters(postParams, getPostParamsEncoding()); } return null; } public byte[] getBody() throws AuthFailureError { Map<String, String> params = getParams(); if (params != null && params.size() > 0) { return encodeParameters(params, getParamsEncoding()); } return null; }
這兩個函數想必大家看函數名稱估計都能明白到底是怎么回事了,只不過這里有個小小的區別...第一個方法僅僅是對Post請求方式中Body實體部分的獲取,而第二個是對Post或Put請求方式中Body實體部分的獲取...
我們知道網絡請求時,信息是以數據報的形式進行傳遞的,數據報有頭部(Headers)和實體(Body)部分...實體一般都是封裝着想要發送的數據以及驗證信息...因此想要獲取Body中的實體數據就必須要通過某種方法來獲取原生態的實體數據(Body)...獲取了實體數據之后,就可以提交驗證以及發送數據...那么上面兩個函數就是用來解決這個問題的...
我們可以從源碼看到,二者分別調用getParams()和getPostParams()函數...
2.2.2 protected Map<String,String> getPostParams() throws AuthFailureError{}
protected Map<String,String> getParams() throws AuthFailureError{}
protected Map<String, String> getPostParams() throws AuthFailureError { return getParams(); } protected Map<String, String> getParams() throws AuthFailureError { return null; }
這兩個方法就是獲取數據報中Body用於驗證或授權時傳遞的參數,通過源碼我們可以看到,方法的返回值是空值,這也不難理解,如果客戶端想要完成驗證和授權,必須要由客戶端發送驗證數據,通過對客戶端驗證數據信息的抓取,接着應用程序重寫上面的兩個方法,客戶端的驗證數據信息被封裝到這兩個方法內,這樣服務器就可以真正的獲取到客戶端提交的信息了..來張圖片方便大家理解...
這里還涉及到了一個參數的編碼...通過調用encodeParamters()方法...
2.2.3 private byte[] encodeParameters(Map<String,String>params,String paramsEncoding){}
這個方法需要對傳遞過來的所有參數進行遍歷...將參數轉化成 postid=4868291&update=1 這樣的形式...我們在訪問網站的時候經常會在url看到這樣類似的字串,那也就是傳遞的參數想必也就不難理解了...
private byte[] encodeParameters(Map<String, String> params, String paramsEncoding) { StringBuilder encodedParams = new StringBuilder(); try { for (Map.Entry<String, String> entry : params.entrySet()) { encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding)); encodedParams.append('='); encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding)); encodedParams.append('&'); } return encodedParams.toString().getBytes(paramsEncoding); } catch (UnsupportedEncodingException uee) { throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee); } }
2.3 請求完成后需要執行的函數...
2.3.1 void finish(final String tag){}
當一個請求完成之后需要對做出一些操作,首先需要做的事情就是將請求隊列中的這次請求進行移除操作,因為請求已經完成...這也不難理解,也就是下面源碼第一個if執行的過程,他會再次調用RequestQueue中finish()函數,來移除這次請求,這個源碼就先不介紹...等到后面介紹RequestQueue源碼的時候再細細說一下...我們只需要知道現在它的功能就行了...也是這個函數的主要部分...而下面第二個if()函數,其實是為了轉儲這次請求中所有的日志文件,為了以后的調試...
void finish(final String tag) { if (mRequestQueue != null) { mRequestQueue.finish(this); } if (MarkerLog.ENABLED) { final long threadId = Thread.currentThread().getId(); if (Looper.myLooper() != Looper.getMainLooper()) { // If we finish marking off of the main thread, we need to // actually do it on the main thread to ensure correct ordering. Handler mainThread = new Handler(Looper.getMainLooper()); mainThread.post(new Runnable() { @Override public void run() { mEventLog.add(tag, threadId); mEventLog.finish(this.toString()); } }); return; } mEventLog.add(tag, threadId); mEventLog.finish(this.toString()); } else { long requestTime = SystemClock.elapsedRealtime() - mRequestBirthTime; if (requestTime >= SLOW_REQUEST_THRESHOLD_MS) { VolleyLog.d("%d ms: %s", requestTime, this.toString()); } } }
2.4 Request的構造函數...
2.4.1 public Request(String url,Response.ErrorListener listener){}
public Request(int method,String url,Response.ErrorListener listener){}
構造函數分為兩種,一個是直接通過url來執行請求,一個是通過指定提交方式,然后通過url來執行請求...
public Request(String url, Response.ErrorListener listener) { this(Method.DEPRECATED_GET_OR_POST, url, listener); } public Request(int method, String url, Response.ErrorListener listener) { mMethod = method; mUrl = url; mErrorListener = listener; setRetryPolicy(new DefaultRetryPolicy()); mDefaultTrafficStatsTag = TextUtils.isEmpty(url) ? 0: Uri.parse(url).getHost().hashCode(); }
Request只是一個抽象接口,為外部暴露接口,從而讓其他的類去實現,其中還有許多的方法,包括請求失敗時的重試策略,以及請求緩存的一些定義...還有許多變量和方法,只是在Request中進行了封裝,而真正去調用和實現這些方法則需要其他的類進行擴展...因此Request的源碼只是做一些簡單的介紹..介紹的也是其中非常重要的方法...其他的內容則在后續進行介紹...