Android-網絡通訊框架Volley使用詳解

1 Volley發送get請求:java


public void getJson() {android

    String url = "http://"+host+":8080/web/json.jsp?username=xjs&password=123456";web

    mQueue.add(new JsonObjectRequest(Method.GET, url, null,json

        new Listener<jsonobject>() {tomcat

            @Overridecookie

            public void onResponse(JSONObject response) {網絡

                Log.e(TAG, "response : " + response.toString());app

            }框架

        }, new Response.ErrorListener() {dom

            @Override

            public void onErrorResponse(VolleyError error) {

                String err = error.getMessage();

                Log.e(TAG, "err : " + err);

            }

        }));

}



///////////////////////////////////////////////////////////////////////////////////////////

2 Volley發送post請求:


public void postJson() {

    String url = "http://"+host+":8080/web/json.jsp";

    StringRequest postRequest = new StringRequest(

            Request.Method.POST, 

            url,

            new Response.Listener<string>() {

                @Override

                public void onResponse(String response) {

                    // response

                    Log.d("Response", response);

                }

            }, new Response.ErrorListener() {

                @Override

                public void onErrorResponse(VolleyError error) {

                    // error

                    Log.d("Error.Response", error.getMessage());

                }

            }) {

        @Override

        protected Map<string, string=""> getParams() {

            Map<string, string=""> params = new HashMap<string, string="">();

            params.put("username", "xjs");

            params.put("password", "123456");

            return params;

        }

    };

    mQueue.add(postRequest);

}


////////////////////////////////////////////////////////////////////////////////////////

3 Volley獲取網絡圖片:


public void getImage() {

    String imageUrl = "http://"+host+":8080/web/image.jsp";

    NetworkImageView view = (NetworkImageView) findViewById(R.id.network_image_view);

    view.setDefaultImageResId(android.R.drawable.ic_menu_rotate); 

    view.setErrorImageResId(android.R.drawable.ic_delete); 

    view.setImageUrl(imageUrl, new ImageLoader(mQueue, new BitmapLruCache(1024 * 4)));

}


////////////////////////////////////////////////////////////////////////////////////////

4 Volley發送Https請求,須要修改源碼:


protected HttpURLConnection createConnection(URL url) throws IOException {

    if (url.toString().toLowerCase(Locale.CHINA).startsWith("https")) {

        HTTPSTrustManager.allowAllSSL();

    }

    return (HttpURLConnection) url.openConnection();

}

//HTTPSTrustManager.java:

public class HTTPSTrustManager implements X509TrustManager {

    private static TrustManager[] trustManagers;

    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {};

    @Override

    public void checkClientTrusted(

            java.security.cert.X509Certificate[] x509Certificates, String s)

            throws java.security.cert.CertificateException {

        // To change body of implemented methods use File | Settings | File

        // Templates.

    }

    @Override

    public void checkServerTrusted(

            java.security.cert.X509Certificate[] x509Certificates, String s)

            throws java.security.cert.CertificateException {

        // To change body of implemented methods use File | Settings | File

        // Templates.

    }

    public boolean isClientTrusted(X509Certificate[] chain) {

        return true;

    }

    public boolean isServerTrusted(X509Certificate[] chain) {

        return true;

    }

    @Override

    public X509Certificate[] getAcceptedIssuers() {

        return _AcceptedIssuers;

    }

    public static void allowAllSSL() {

        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

            @Override

            public boolean verify(String arg0, SSLSession arg1) {

                // TODO Auto-generated method stub

                return true;

            }

        });

        SSLContext context = null;

        if (trustManagers == null) {

            trustManagers = new TrustManager[] { new HTTPSTrustManager() };

        }

        try {

            context = SSLContext.getInstance("TLS");

            context.init(null, trustManagers, new SecureRandom());

        } catch (NoSuchAlgorithmException e) {

            e.printStackTrace();

        } catch (KeyManagementException e) {

            e.printStackTrace();

        }

        HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());

    }

}


////////////////////////////////////////////////////////////////////////////////////////

5 Volley獲取服務端返回的cookie,須要修改源碼:


@Override

public HttpResponse performRequest(Request<!--?--> request,Map<string, string=""> additionalHeaders) 

    throws IOException,AuthFailureError {

    for (Entry<string, list<string="">> header : connection.getHeaderFields().entrySet()) {

    if (header.getKey() != null) {

        String key = header.getKey();

        List<string> values = header.getValue();

        if(key.equalsIgnoreCase("set-cookie")){

            StringBuilder cookieString = new StringBuilder();

            for(String value : values){

                cookieString.append(value).append("\n");//用\n做爲分隔符,cookie中不該該有回車符號

            }

            cookieString.deleteCharAt(cookieString.length() - 1);

            Header h = new BasicHeader(header.getKey(), cookieString.toString());

            response.addHeader(h);

        }else{

            Header h = new BasicHeader(header.getKey(), values.get(0));

            response.addHeader(h);

        }

    }

}

}

//而後再request中重寫parseNetworkResponse():

@Override

protected Response<string> parseNetworkResponse(NetworkResponse response) {

    Response<string> superResponse = super.parseNetworkResponse(response);

    Map<string, string=""> responseHeaders = response.headers;

    String rawCookies = responseHeaders.get("Set-Cookie");

    //服務端返回是 set-cookie:JSESSIONID=D90B58454550B4D37C4B66A76BF27B93; Path=/otn BIGipServerotn=2564030730.64545.0000; path=/

    String part1 = substring(rawCookies, "", ";");

    String part2 = substring(rawCookies, "\n", ";");

    //客戶端須要的是 cookie:JSESSIONID=D90B58454550B4D37C4B66A76BF27B93; BIGipServerotn=2564030730.64545.0000;

    cookies = part1 + "; " + part2 + ";";

    return superResponse;

}



////////////////////////////////////////////////////////////////////////////////////////

6 Volley發請求的時候上傳cookie,在request中重寫getHeaders():


@Override

public Map<string, string="">getHeaders() throws AuthFailureError {

         if(cookies!= null && cookies.length() > 0){

                   HashMap<string,string>         headers = newHashMap<string, string="">();

                   headers.put("Cookie",cookies);

                   returnheaders;

         }

         returnsuper.getHeaders();

}


////////////////////////////////////////////////////////////////////////////////////////

7 Volley自定義request:

public class ByteArrayRequest extends Request<byte[]>{

    private final Listener<byte[]> mListener;

    public ByteArrayRequest(int method, String url, Listener<byte[]> listener, ErrorListener errlistener) {

        super(method, url, errlistener);

        mListener = listener;

    }

    @Override

    protected Response<byte[]> parseNetworkResponse(NetworkResponse response) {

        if(response == null){

            return null;

        }

        if(response.statusCode != HttpStatus.SC_OK){

            return null;

        }

        byte[] bytes = response.data;

        return Response.success(bytes, null);

    }

    @Override

    protected void deliverResponse(byte[] response) {

        if(mListener != null){

            mListener.onResponse(response);

        }

    }

}



////////////////////////////////////////////////////////////////////////////////////////

8 Volley設置請求超時時間:

@Override

public RetryPolicy getRetryPolicy() { 

         RetryPolicyretryPolicy = new DefaultRetryPolicy(5000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT); 

         returnretryPolicy; 

}


//////////////////////////////////////////////////////////////////////////////////////////////

附一個登錄鐵道部12306的例子,源碼在:http://download.csdn.net/download/goldenfish1919/7029907

Ps:我在測試的時候用了本地的一個tomcat,一塊打包放在了asserts下面。

參考:

http://blog.csdn.net/xyz_lmn/article/details/12165391

http://blog.csdn.net/xyz_lmn/article/details/12746581

http://blog.csdn.net/xyz_lmn/article/details/12177005

http://www.itsalif.info/content/android-volley-tutorial-http-get-post-put

概述:http://blog.csdn.net/t12x3456/article/details/9221611

入門: http://blog.csdn.net/ttdevs/article/details/17566795

自定義request: http://blog.csdn.net/ttdevs/article/details/17586205

源碼分析:http://blog.csdn.net/ttdevs/article/details/17764351

發送https請求:http://blog.csdn.net/llwdslal/article/details/18052723

構造cache:http://stackoverflow.com/questions/16682595/android-volley-imageloader-bitmaplrucache-parameter

解析服務端cookie:http://stackoverflow.com/questions/20702178/android-volley-access-http-response-header-fields,http://blog.csdn.net/hpb21/article/details/12163371

上傳cookie:http://stackoverflow.com/questions/17049473/how-to-set-custom-header-in-volley-request

設置超時:http://stackoverflow.com/questions/17094718/android-volley-timeout

http://blog.csdn.net/dacainiao007/article/details/12617747,這裏關於超時時間增加的因子的說法不許確,應該是當第一次鏈接超時之後,第二次超時時間會變爲原來的多少倍,鏈接超時和讀取超時設置爲同一個數。



/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 在android中基於http請求的框架不少,本身若是比較瞭解http請求流程,本身也能夠寫一個不錯的框架,因爲一些緣由,項目中咱們本身開發的框架被要求用volley替換掉了,所以我不得不對volley這個開發包進行本身的研究,以但願可以熟悉整個流程,以及可以順利的將這個開源包融入到項目中同時不會影響原有邏輯。(我的風格的緣由吧,我不是很喜歡貼大段大段的代碼在帖子裏面,你們若是能對照volley源碼來看這個帖子的話,會更有收穫的)

      

       首先囉嗦些本身對android的http請求框架的一些感悟,若是有不對的地方你們盡情拍磚拍死我吧(就算死了我也要發帖子)。

      

       我理解的基於網絡的應用最核心的其實就是request跟response的分發。這個分發機制寫好了,框架夠健壯,擴展性高,那麼之後涉及到這個層次的改動就少(由於從一開始咱們的設計都是比較初級的,會隨着需求的不斷增多而出現一些須要對框架機制的改動需求),由於對於分發機制的改動是很核心的,說牽一髮而動全身一點也不爲過,稍微改一點點都會對項目有很大的影響甚至是未知的影響,並且構建得很差的話,有些需求的改動會很是麻煩,而這些改動若是是良好的構架的話每每是能夠避免的,因此,在初期可以構建好一些是頗有必要的。我大概看過一些開源的項目以及這些年來本身作過的項目(沒作過遊戲,因此遊戲的我不知道哈),感受基於網絡的應用要麼用http要麼用套接字,若是不須要推送的,通常都是使用http來作。


       http的請求步驟大概分爲這麼幾步,就我看來:

       1)發起request,這裏的發起者要是個context之類的(通常是activity或者service)東東,固然不少時候發起者也是最後數據的接受者。不一樣的框架對於這個發起的機制實現各不相同,但總的說來都是統一給出一個公共接口,讓發起者封裝好必要的信息,使用公共接口,讓其實現類去啓動實際的http請求操做,大概主要區別在於如何封裝這些request信息。

       

       2)進行request請求,並獲取response。真正的請求和響應就在這裏完成,這裏可能有兩個須要考慮到的,一個是線程的阻塞,有的框架會讓線程阻塞直到獲取到響應爲止,有的框架則會在這裏分發出多個線程,以免這種阻塞,固然大多數都會採用後者了。二個就是數據的存儲,有些固定的請求,好比一些不會輕易變更的信息,在第一次請求到了以後就不須要再屢次請求了,通常也能夠在這個部分完成這個功能。但總而言之,無論你線程分配也好,使用本地數據也好,仍是你的請求出問題了也好,總之你必須在必定的時間內,給個人request一個response。

      

       3)分派response,咱們去餐館吃飯都知道,哪桌點的菜就端到哪桌去,不能端錯了。誰發出的request,最後就要給到他的接受者手裏,不能給錯了。有些框架是靠一些接口類的注入來保證數據的正確接受,有些框架是靠一個尋找機制來保障的(好比廣播)。


       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

     這個大牛對volley的一個感性理解:

       好了,說了這麼多咱們來看看volley吧。前面那麼多鋪墊也不是白用的,我就按照我理解的這三步來拆析volley框架。

      1)發起request:volley使用Request抽象類來封裝請求。Request類也是整個volley項目中最核心的類(還真沒有之一)。從源碼咱們能夠看到,Request的實現類有好幾種,而這些實現類有個共同的特色就是他們其實已經定義好了response返回的數據類型,也就是說,其實這裏的Requst類並不僅僅只作request,他們也負責對response的數據處理(固然直接使用實現類的話,咱們通常無論這些數據如何被處理的),咱們能夠本身寫實現類並實現其中的數據處理方法

         abstract protected Response<T> parseNetworkResponse(NetworkResponse response);

         來將返回數據變成咱們想要的類型,而後由咱們再來進一步加工處理。

         Request可不僅僅只作了這麼一件事情。爲了證實他爲何是最核心的類,我再列舉幾個他作了的貌似跟他不相關的事情。

         abstract protected void deliverResponse(T response);

         public void deliverError(VolleyError error) 

         有木有震驚的趕腳,是的,最後response以及error的分發的實際執行者也是Request。因此這個Request類是貫穿一個請求到響應過程自始至終的類。這個其實不難理解,最後一步的分派工做須要必定的信息來保證分派的正確性,而最能提供這些信息的,其實就是最初咱們發出的request了。

         簡單的介紹下Request如何使用:

         從源碼能夠看出

            getUrl 是返回的 url地址,

            getBody是返回的請求參數,這兩個方法是在http的實際請求中確定要用到的,使用get請求的話是須要保證getUrl的返回值正確便可,而使用post的話還要保證後面一個方法的返回值正確。

            (返回值如何注入就是大家的事情了,構造函數注入也可,set 方法注入也可)

            這裏須要給你們注意的地方原生態的Stringrequest 沒有重寫 getBody 方法,也就是說 getBody 返回爲null,那麼 volley將默認使用get請求,若是你們想用post請求並使用Stringrequest的話,請重寫這個方法。

          另外還有兩個很重要的類,請你們在構造request的時候務必要注入,

          ErrorListener 和 Listener,一個是用來處理error(public void onErrorResponse(VolleyError error))的,一個是用來處理正常返回的(public void onResponse(T response))這兩個接口的定義都在Response類中。不難想出上面我所說的兩個方法abstract protected void deliverResponse(T response)和public void deliverError(VolleyError error) 的實現其實就是調用這兩個接口各自的方法就能夠了。

          有些附加的條件咱們能夠酌情的考慮是否須要實現。

          public String getCacheKey(),CacheKey是volley從Request獲取的用於本地存儲請求數據的鍵值,相信你們很快能明白,若是兩個request的這個方法返回的值同樣的話,後者將可以有機會取到前者存儲在本地的數據,從而減小了網絡請求。原生態的Request是使用url爲cechekey,這樣並不必定科學,有本地存儲需求的童鞋,請切記重寫此方法。固然前提是保證 public final boolean shouldCache()返回爲true。不然前功盡棄。

           public void setRetryPolicy(RetryPolicy retryPolicy),從字面意思就能夠看出,這個是對一個request的從新請求策略的設置,不一樣的項目是否須要從新請求,從新請求幾回,請求超時的時間,這些就在這設置到裏面。通常放就是繼承RetryPolicy 類,根據本身的需求實現父類方法。

          不知不覺寫了這麼多,先寫到這裏吧,後面我再介紹volley如何實現第二步跟第三步。

相關文章
相關標籤/搜索