Android 學習筆記之Volley開源框架解析(一)


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的源碼只是做一些簡單的介紹..介紹的也是其中非常重要的方法...其他的內容則在后續進行介紹...

 

 

     

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM