Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android網絡框架Volley

Android網絡框架Volley

編輯:關於Android編程

Volley是Google I/O 2013推出的網絡通信庫,在volley推出之前我們一般會選擇比較成熟的第三方網絡通信庫,如:

android-async-http

retrofit

okhttp

他們各有優劣,之前個人則比較喜歡用Android-async-http, 如今Google推出了官方的針對Android平台上的網絡通信庫,能使網絡通信更快,更簡單,更健壯,Volley在提供了高性能網絡通訊功能的同時,對網絡圖片加載也提供了良好的支持,完全可以滿足簡單REST客戶端的需求, 我們沒有理由不跟上時代的潮流

 

使用Volley

 

下載Volley源碼並build jar包。

$ git clone https://android.googlesource.com/platform/frameworks/volley
$ cd volley
$ android update project -p
$ ant jar

然後把生成的jar包引用到我們的項目中,extras目錄下則包含了目前最新的volley源碼。

說明

此Demo主要介紹了日常網絡開發常用的基本功能,但volley的擴展性很強,可以根據需要定制你自己的網絡請求。

volley視頻地址:http://www.youtube.com/watch?v=yhv8l9F44qo&feature=player_embedded

\

以上是在Google IO的演講上ppt的配圖,從上面這張圖我們可以看出,volley適合快速,簡單的請求(Json對象,圖片加載)。

volley的特性:

 

    • JSON,圖像等的異步下載;
    • 網絡請求的排序(scheduling)
    • 網絡請求的優先級處理
    • 緩存
    • 多級別取消請求
    • 和Activity和生命周期的聯動(Activity結束時同時取消所有網絡請求)

       

      接下來,我們來學習簡單的使用下volley給我提供的API吧。

      1.首先拿到一個請求隊列(RequestQueue只需要一個實例即可,不像AsyncTask每次使用都要new一個)

       

      [java]view plaincopy    
      1. //初始化RequestQueue一個activity只需要一個
      2. privatevoidinitRequestQueue(){
      3. mQueue=Volley.newRequestQueue(getApplicationContext());
      4. }
        2.實現volley的異步請求類(JsonObjectRequest,JsonArrayRequest,StringRequest,ImageRequest)

         

        由於用法都相差不大,我就不一一舉例了,舉幾個常用有代表性的例子:

        以下代碼是StringRequest的get請求:

        [java]view plaincopy    
        1. //get請求 [java]view plaincopy    
          1. privatevoidloadGetStr(Stringurl){
          2.  
          3. StringRequestsrReq=newStringRequest(Request.Method.GET,url,
          4. newStrListener(),newStrErrListener()){
          5.  
          6. protectedfinalStringTYPE_UTF8_CHARSET="charset=UTF-8";
          7.  
          8. //重寫parseNetworkResponse方法改變返回頭參數解決亂碼問題
          9. //主要是看服務器編碼,如果服務器編碼不是UTF-8的話那麼就需要自己轉換,反之則不需要
          10. @Override
          11. protectedResponseparseNetworkResponse(
          12. NetworkResponseresponse){
          13. try{
          14. Stringtype=response.headers.get(HTTP.CONTENT_TYPE);
          15. if(type==null){
          16. type=TYPE_UTF8_CHARSET;
          17. response.headers.put(HTTP.CONTENT_TYPE,type);
          18. }elseif(!type.contains("UTF-8")){
          19. type+=";"+TYPE_UTF8_CHARSET;
          20. response.headers.put(HTTP.CONTENT_TYPE,type);
          21. }
          22. }catch(Exceptione){
          23. }
          24. returnsuper.parseNetworkResponse(response);
          25. }
          26. };
          27. srReq.setShouldCache(true);//控制是否緩存
          28. startVolley(srReq);
          29. }
            以下代碼是JsonObjectRequest的post請求: [java]view plaincopy    
            1. //post請求
            2. privatevoidloadPostJson(Stringurl){
            3. //第二個參數說明:
            4. //ConstructorwhichdefaultstoGETifjsonRequestisnull,POST
            5. //otherwise.
            6. //默認情況下設成null為get方法,否則為post方法。
            7. JsonObjectRequestsrReq=newJsonObjectRequest(url,null,
            8. newJsonListener(),newStrErrListener()){
            9.  
            10. @Override
            11. protectedMapgetParams()throwsAuthFailureError{
            12. Mapmap=newHashMap();
            13. map.put("w","2459115");
            14. map.put("u","f");
            15. returnmap;
            16. }
            17. };
            18. srReq.setShouldCache(false);//控制是否緩存
            19. startVolley(srReq);
            20. }
              大家注意看的話,無論是JsonObjectReques的postt還是StringRequest的get都需要傳入兩個監聽函數一個是成功一個是失敗,成功監聽他們會返回相應類型的數據:

               

              [java]view plaincopy    
              1. //Str請求成功回調
              2. privateclassStrListenerimplementsListener{
              3.  
              4. @Override
              5. publicvoidonResponse(Stringarg0){
              6. Log.e(Tag,arg0);
              7.  
              8. }
              9.  
              10. }
              11.  
              12. //Gson請求成功回調
              13. privateclassGsonListenerimplementsListener{
              14.  
              15. @Override
              16. publicvoidonResponse(ErrorRsparg0){
              17. Toast.makeText(mContext,arg0.toString(),Toast.LENGTH_LONG).show();
              18. }
              19.  
              20. }
              21. //共用失敗回調
              22. privateclassStrErrListenerimplementsErrorListener{
              23.  
              24. @Override
              25. publicvoidonErrorResponse(VolleyErrorarg0){
              26. Toast.makeText(mContext,
              27. VolleyErrorHelper.getMessage(arg0,mContext),
              28. Toast.LENGTH_LONG).show();
              29. }
              30.  
              31. } 接下來是ImageRequest [java]view plaincopy    
                1. /**
                2. *第三第四個參數分別用於指定允許圖片最大的寬度和高度,如果指定的網絡圖片的寬度或高度大於這裡的最大值,則會對圖片進行壓縮,
                3. *指定成0的話就表示不管圖片有多大,都不會進行壓縮。
                4. *
                5. *@paramurl
                6. *圖片地址
                7. *@paramlistener
                8. *@parammaxWidth
                9. *指定允許圖片最大的寬度
                10. *@parammaxHeight
                11. *指定允許圖片最大的高度
                12. *@paramdecodeConfig
                13. *指定圖片的顏色屬性,Bitmap.Config下的幾個常量.
                14. *@paramerrorListener
                15. */
                16. privatevoidgetImageRequest(finalImageViewiv,Stringurl){
                17. ImageRequestimReq=newImageRequest(url,newListener(){
                18.  
                19. @Override
                20. publicvoidonResponse(Bitmaparg0){
                21. iv.setImageBitmap(arg0);
                22. }
                23. },60,60,Bitmap.Config.ARGB_8888,newStrErrListener());
                24. startVolley(imReq);
                25. } 看到現在大家肯定會疑惑寫了這麼多不同類型的Request到底如何運行?接下請看:

                   

                   

                  [java]view plaincopy    
                  1. //添加及開始請求
                  2. privatevoidstartVolley(Requestreq){
                  3.  
                  4. //設置超時時間
                  5. //req.setRetryPolicy(newDefaultRetryPolicy(20*1000,1,1.0f));
                  6. //將請求加入隊列
                  7. mQueue.add(req);
                  8. //開始發起請求
                  9. mQueue.start();
                  10. }

                    volley不僅提供了這些請求的方式,還提供了加載圖片的一些方法和控件:

                    比如我們一個列表需要加載很多圖片我們可以使用volley給我們提供的ImageLoader(ImageLoader比ImageRequest更加高效,因為它不僅對圖片進行緩存,還可以過濾掉重復的鏈接,避免重復發送請求。)

                     

                    [java]view plaincopy    
                    1. publicclassImageAdapterextendsArrayAdapter{
                    2.  
                    3. privateRequestQueuemQueue;
                    4. privateImageLoadermImageLoader;
                    5.  
                    6. publicImageAdapter(Contextcontext,Listobjects){
                    7. super(context,0,objects);
                    8. mQueue=Volley.newRequestQueue(getContext());
                    9. mImageLoader=newImageLoader(mQueue,newBitmapCache());
                    10. }
                    11.  
                    12. @Override
                    13. publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
                    14. Stringurl=getItem(position);
                    15. ImageViewimageView;
                    16. if(convertView==null){
                    17. imageView=newImageView(getContext());
                    18. }else{
                    19. imageView=(ImageView)convertView;
                    20. }
                    21. //getImageListener(imageView控件對象,默認圖片地址,失敗圖片地址);
                    22. ImageListenerlistener=ImageLoader.getImageListener(imageView,android.R.drawable.ic_menu_rotate,android.R.drawable.ic_delete);
                    23. //get(圖片地址,listener,寬,高);自動幫你處理圖片的寬高再也不怕大圖片的oom了
                    24. mImageLoader.get(url,listener,100,200);
                    25. returnimageView;
                    26. }
                    27.  
                    28. } 當然還需要重寫ImageCache這個類 //使用LruCache再也不用怕加載多張圖片oom了

                       

                       

                      [java]view plaincopy    
                      1. publicclassBitmapCacheextendsLruCacheimplementsImageCache{
                      2. //LruCache原理:Cache保存一個強引用來限制內容數量,每當Item被訪問的時候,此Item就會移動到隊列的頭部。當cache已滿的時候加入新的item時,在隊列尾部的item會被回收。
                      3. //解釋:當超出指定內存值則移除最近最少用的圖片內存
                      4. publicstaticintgetDefaultLruCacheSize(){
                      5. //拿到最大內存
                      6. finalintmaxMemory=(int)(Runtime.getRuntime().maxMemory()/1024);
                      7. //拿到內存的八分之一來做圖片內存緩存
                      8. finalintcacheSize=maxMemory/8;
                      9.  
                      10. returncacheSize;
                      11. }
                      12.  
                      13. publicBitmapLruCache(){
                      14. this(getDefaultLruCacheSize());
                      15. }
                      16.  
                      17. publicBitmapLruCache(intsizeInKiloBytes){
                      18. super(sizeInKiloBytes);
                      19. }
                      20.  
                      21. @Override
                      22. protectedintsizeOf(Stringkey,Bitmapvalue){
                      23. returnvalue.getRowBytes()*value.getHeight()/1024;
                      24. }
                      25.  
                      26. @Override
                      27. publicBitmapgetBitmap(Stringurl){
                      28. returnget(url);
                      29. }
                      30.  
                      31. @Override
                      32. publicvoidputBitmap(Stringurl,Bitmapbitmap){
                      33. put(url,bitmap);
                      34. }
                      35. }
                        Volley還提供的加載圖片的控件com.android.volley.NetworkImageView。(這個控件在被從父控件detach的時候,會自動取消網絡請求的,即完全不用我們擔心相關網絡請求的生命周期問題,而且NetworkImageView還會根據你對圖片設置的width和heigh自動壓縮該圖片不會產生多的內存,還有NetworkImageView在列表中使用不會圖片錯誤)

                         

                         

                        [html]view plaincopy    
                        1. android:id="@+id/network_image_view"
                        2. android:layout_width="100dp"
                        3. android:layout_height="100dp"/> 使用方法:

                           

                           

                          [java]view plaincopy    
                          1. privatevoidnetworkImageViewUse(NetworkImageViewiv,Stringurl){
                          2. ImageLoaderimLoader=newImageLoader(mQueue,newBitmapLruCache());
                          3. iv.setDefaultImageResId(R.drawable.ic_launcher);
                          4. iv.setErrorImageResId(R.drawable.ic_launcher);
                          5. iv.setImageUrl(url,imLoader);
                          6. }
                            我們說了這麼多都是請求,那麼如何取消請求呢?

                             

                            1.activity自動銷毀時它會自定取消所有請求。

                            2.給請求設置標簽:

                             

                            [java]view plaincopy    
                            1. request.setTag("MyTag");

                               

                              取消所有指定標記的請求:

                               

                              [java]view plaincopy    
                              1. request.cancelAll("MyTag"); Volley的架構設計:

                                 

                                \


                                其中藍色部分代表主線程,綠色部分代表緩存線程,橙色部分代表網絡線程。我們在主線程中調用RequestQueue的add()方法來添加一條網絡請求,這條請求會先被加入到緩存隊列當中,如果發現可以找到相應的緩存結果就直接讀取緩存並解析,然後回調給主線程。如果在緩存中沒有找到結果,則將這條請求加入到網絡請求隊列中,然後處理發送HTTP請求,解析響應結果,寫入緩存,並回調主線程。

                                 

                                 

                                接下來我們要看看如何把volley使用到實戰項目裡面,我們先考慮下一些問題:

                                從上一篇來看mQueue 只需要一個對象即可,new RequestQueue對象對資源一種浪費,我們應該在application,以及可以把取消請求的方法也在application進行統一管理,看以下代碼:

                                 

                                [java]view plaincopy    
                                1. packagecom.chronocloud.lib.base;
                                2.  
                                3. importandroid.app.Application;
                                4. importandroid.text.TextUtils;
                                5.  
                                6. importcom.android.volley.Request;
                                7. importcom.android.volley.RequestQueue;
                                8. importcom.android.volley.VolleyLog;
                                9. importcom.android.volley.toolbox.Volley;
                                10.  
                                11. publicclassApplicationControllerextendsApplication{
                                12.  
                                13. /**
                                14. *LogorrequestTAG
                                15. */
                                16. publicstaticfinalStringTAG="VolleyPatterns";
                                17.  
                                18. /**
                                19. *GlobalrequestqueueforVolley
                                20. */
                                21. privateRequestQueuemRequestQueue;
                                22.  
                                23. /**
                                24. *Asingletoninstanceoftheapplicationclassforeasyaccessinother
                                25. *places
                                26. */
                                27. privatestaticApplicationControllersInstance;
                                28.  
                                29. @Override
                                30. publicvoidonCreate(){
                                31. super.onCreate();
                                32.  
                                33. //initializethesingleton
                                34. sInstance=this;
                                35. }
                                36.  
                                37. /**
                                38. *@returnApplicationControllersingletoninstance
                                39. */
                                40. publicstaticsynchronizedApplicationControllergetInstance(){
                                41. returnsInstance;
                                42. }
                                43.  
                                44. /**
                                45. *@returnTheVolleyRequestqueue,thequeuewillbecreatedifitisnull
                                46. */
                                47. publicRequestQueuegetRequestQueue(){
                                48. //lazyinitializetherequestqueue,thequeueinstancewillbe
                                49. //createdwhenitisaccessedforthefirsttime
                                50. if(mRequestQueue==null){
                                51. //1
                                52. //2
                                53. synchronized(ApplicationController.class){
                                54. if(mRequestQueue==null){
                                55. mRequestQueue=Volley
                                56. .newRequestQueue(getApplicationContext());
                                57. }
                                58. }
                                59. }
                                60. returnmRequestQueue;
                                61. }
                                62.  
                                63. /**
                                64. *Addsthespecifiedrequesttotheglobalqueue,iftagisspecifiedthen
                                65. *itisusedelseDefaultTAGisused.
                                66. *
                                67. *@paramreq
                                68. *@paramtag
                                69. */
                                70. publicvoidaddToRequestQueue(Requestreq,Stringtag){
                                71. //setthedefaulttagiftagisempty
                                72. req.setTag(TextUtils.isEmpty(tag)?TAG:tag);
                                73.  
                                74. VolleyLog.d("Addingrequesttoqueue:%s",req.getUrl());
                                75.  
                                76. getRequestQueue().add(req);
                                77. }
                                78.  
                                79. /**
                                80. *AddsthespecifiedrequesttotheglobalqueueusingtheDefaultTAG.
                                81. *
                                82. *@paramreq
                                83. *@paramtag
                                84. */
                                85. publicvoidaddToRequestQueue(Requestreq){
                                86. //setthedefaulttagiftagisempty
                                87. req.setTag(TAG);
                                88.  
                                89. getRequestQueue().add(req);
                                90. }
                                91.  
                                92. /**
                                93. *CancelsallpendingrequestsbythespecifiedTAG,itisimportantto
                                94. *specifyaTAGsothatthepending/ongoingrequestscanbecancelled.
                                95. *
                                96. *@paramtag
                                97. */
                                98. publicvoidcancelPendingRequests(Objecttag){
                                99. if(mRequestQueue!=null){
                                100. mRequestQueue.cancelAll(tag);
                                101. }
                                102. }
                                103. } 接下來就是Volley雖然給我們提供了很多不同的Request(JsonObjectRequest,JsonArrayRequest,StringRequest,ImageRequest),但是還是滿足不了我們實戰中的需求,我們實戰開發中經常用到的是xml格式,Gson解析。

                                   

                                  接下來我們來看看,如何自定義Request

                                  XmlRequest:

                                   

                                  [java]view plaincopy    
                                  1. publicclassXMLRequestextendsRequest{
                                  2.  
                                  3. privatefinalListenermListener;
                                  4.  
                                  5. publicXMLRequest(intmethod,Stringurl,Listenerlistener,
                                  6. ErrorListenererrorListener){
                                  7. super(method,url,errorListener);
                                  8. mListener=listener;
                                  9. }
                                  10.  
                                  11. publicXMLRequest(Stringurl,Listenerlistener,ErrorListenererrorListener){
                                  12. this(Method.GET,url,listener,errorListener);
                                  13. }
                                  14.  
                                  15. @Override
                                  16. protectedResponseparseNetworkResponse(NetworkResponseresponse){
                                  17. try{
                                  18. StringxmlString=newString(response.data,
                                  19. HttpHeaderParser.parseCharset(response.headers));
                                  20. XmlPullParserFactoryfactory=XmlPullParserFactory.newInstance();
                                  21. XmlPullParserxmlPullParser=factory.newPullParser();
                                  22. xmlPullParser.setInput(newStringReader(xmlString));
                                  23. returnResponse.success(xmlPullParser,HttpHeaderParser.parseCacheHeaders(response));
                                  24. }catch(UnsupportedEncodingExceptione){
                                  25. returnResponse.error(newParseError(e));
                                  26. }catch(XmlPullParserExceptione){
                                  27. returnResponse.error(newParseError(e));
                                  28. }
                                  29. }
                                  30.  
                                  31. @Override
                                  32. protectedvoiddeliverResponse(XmlPullParserresponse){
                                  33. mListener.onResponse(response);
                                  34. }
                                  35.  
                                  36. }
                                    GsonRequest(注意需要自行導入gson.jar):

                                     

                                     

                                    [java]view plaincopy    
                                    1. publicclassGsonRequestextendsRequest{
                                    2.  
                                    3. privatefinalListenermListener;
                                    4.  
                                    5. privateGsonmGson;
                                    6.  
                                    7. privateClassmClass;
                                    8.  
                                    9. publicGsonRequest(intmethod,Stringurl,Classclazz,Listenerlistener,
                                    10. ErrorListenererrorListener){
                                    11. super(method,url,errorListener);
                                    12. mGson=newGson();
                                    13. mClass=clazz;
                                    14. mListener=listener;
                                    15. }
                                    16.  
                                    17. publicGsonRequest(Stringurl,Classclazz,Listenerlistener,
                                    18. ErrorListenererrorListener){
                                    19. this(Method.GET,url,clazz,listener,errorListener);
                                    20. }
                                    21.  
                                    22. @Override
                                    23. protectedResponseparseNetworkResponse(NetworkResponseresponse){
                                    24. try{
                                    25. StringjsonString=newString(response.data,
                                    26. HttpHeaderParser.parseCharset(response.headers));
                                    27. returnResponse.success(mGson.fromJson(jsonString,mClass),
                                    28. HttpHeaderParser.parseCacheHeaders(response));
                                    29. }catch(UnsupportedEncodingExceptione){
                                    30. returnResponse.error(newParseError(e));
                                    31. }
                                    32. }
                                    33.  
                                    34. @Override
                                    35. protectedvoiddeliverResponse(Tresponse){
                                    36. mListener.onResponse(response);
                                    37. }
                                    38.  
                                    39. } 接下只差最後一步了就是封裝它的錯誤處理,使用過volley的都知道,volley的監聽錯誤提示都是NoConnectionError。。。等等,這類的錯誤提示,顯然這不是我們想給用戶呈現的錯誤提示,因為就算提示了用戶也不明白什麼意思,所以我們還要封裝一下,能讓用戶看的更清楚的理解這些錯誤提示。ym—— Android網絡框架Volley(體驗篇)我們講過每個請求都需要設置一個失敗的監聽:

                                       

                                       

                                      [java]view plaincopy    
                                      1. //共用失敗回調
                                      2. privateclassStrErrListenerimplementsErrorListener{
                                      3.  
                                      4. @Override
                                      5. publicvoidonErrorResponse(VolleyErrorarg0){
                                      6. Toast.makeText(mContext,
                                      7. VolleyErrorHelper.getMessage(arg0,mContext),
                                      8. Toast.LENGTH_LONG).show();
                                      9. }
                                      10.  
                                      11. } 以上代碼有個VolleyError對象,我們可以從這個對象上下手:

                                         

                                         

                                        [java]view plaincopy    
                                        1. packagecom.example.volley;
                                        2.  
                                        3. importjava.util.HashMap;
                                        4. importjava.util.Map;
                                        5.  
                                        6. importandroid.content.Context;
                                        7.  
                                        8. importcom.android.volley.AuthFailureError;
                                        9. importcom.android.volley.NetworkError;
                                        10. importcom.android.volley.NetworkResponse;
                                        11. importcom.android.volley.NoConnectionError;
                                        12. importcom.android.volley.ServerError;
                                        13. importcom.android.volley.TimeoutError;
                                        14. importcom.android.volley.VolleyError;
                                        15. importcom.google.gson.Gson;
                                        16. importcom.google.gson.reflect.TypeToken;
                                        17. //正如前面代碼看到的,在創建一個請求時,需要添加一個錯誤監聽onErrorResponse。如果請求發生異常,會返回一個VolleyError實例。
                                        18. //以下是Volley的異常列表:
                                        19. //AuthFailureError:如果在做一個HTTP的身份驗證,可能會發生這個錯誤。
                                        20. //NetworkError:Socket關閉,服務器宕機,DNS錯誤都會產生這個錯誤。
                                        21. //NoConnectionError:和NetworkError類似,這個是客戶端沒有網絡連接。
                                        22. //ParseError:在使用JsonObjectRequest或JsonArrayRequest時,如果接收到的JSON是畸形,會產生異常。
                                        23. //SERVERERROR:服務器的響應的一個錯誤,最有可能的4xx或5xxHTTP狀態代碼。
                                        24. //TimeoutError:Socket超時,服務器太忙或網絡延遲會產生這個異常。默認情況下,Volley的超時時間為2.5秒。如果得到這個錯誤可以使用RetryPolicy。
                                        25.  
                                        26. publicclassVolleyErrorHelper{
                                        27.  
                                        28. /**
                                        29. *Returnsappropriatemessagewhichistobedisplayedtotheuseragainst
                                        30. *thespecifiederrorobject.
                                        31. *
                                        32. *@paramerror
                                        33. *@paramcontext
                                        34. *@return
                                        35. */
                                        36. publicstaticStringgetMessage(Objecterror,Contextcontext){
                                        37. if(errorinstanceofTimeoutError){
                                        38. returncontext.getResources().getString(
                                        39. R.string.generic_server_down);
                                        40. }elseif(isServerProblem(error)){
                                        41. returnhandleServerError(error,context);
                                        42. }elseif(isNetworkProblem(error)){
                                        43. returncontext.getResources().getString(R.string.no_internet);
                                        44. }
                                        45. returncontext.getResources().getString(R.string.generic_error);
                                        46. }
                                        47.  
                                        48. /**
                                        49. *Determineswhethertheerrorisrelatedtonetwork
                                        50. *
                                        51. *@paramerror
                                        52. *@return
                                        53. */
                                        54. privatestaticbooleanisNetworkProblem(Objecterror){
                                        55. return(errorinstanceofNetworkError)
                                        56. ||(errorinstanceofNoConnectionError);
                                        57. }
                                        58.  
                                        59. /**
                                        60. *Determineswhethertheerrorisrelatedtoserver
                                        61. *
                                        62. *@paramerror
                                        63. *@return
                                        64. */
                                        65. privatestaticbooleanisServerProblem(Objecterror){
                                        66. return(errorinstanceofServerError)
                                        67. ||(errorinstanceofAuthFailureError);
                                        68. }
                                        69.  
                                        70. /**
                                        71. *Handlestheservererror,triestodeterminewhethertoshowastock
                                        72. *messageortoshowamessageretrievedfromtheserver.
                                        73. *
                                        74. *@paramerr
                                        75. *@paramcontext
                                        76. *@return
                                        77. */
                                        78. privatestaticStringhandleServerError(Objecterr,Contextcontext){
                                        79. VolleyErrorerror=(VolleyError)err;
                                        80.  
                                        81. NetworkResponseresponse=error.networkResponse;
                                        82.  
                                        83. if(response!=null){
                                        84. switch(response.statusCode){
                                        85. case404:
                                        86. case422:
                                        87. case401:
                                        88. try{
                                        89. //servermightreturnerrorlikethis{"error":
                                        90. //"Someerroroccured"}
                                        91. //Use"Gson"toparsetheresult
                                        92. HashMapresult=newGson().fromJson(
                                        93. newString(response.data),
                                        94. newTypeToken>(){
                                        95. }.getType());
                                        96.  
                                        97. if(result!=null&&result.containsKey("error")){
                                        98. returnresult.get("error");
                                        99. }
                                        100.  
                                        101. }catch(Exceptione){
                                        102. e.printStackTrace();
                                        103. }
                                        104. //invalidrequest
                                        105. returnerror.getMessage();
                                        106.  
                                        107. default:
                                        108. returncontext.getResources().getString(
                                        109. R.string.generic_server_down);
                                        110. }
                                        111. }
                                        112. returncontext.getResources().getString(R.string.generic_error);
                                        113. }
                                        114. }
                                          以上代碼中引用的xml是:

                                           

                                           

                                          [html]view plaincopy    
                                          1. 無網絡連接~!
                                          2. 連接服務器失敗~!
                                          3. 網絡異常,請稍後再試~! 接下來,數據請求這一塊已經說完了,我們來說下圖片這一塊,我個人喜歡使用universal-image-loader而不是volley自己提供的(個人認為使用起來universal-image-loader更便捷一些)。

                                             

                                             

                                            下面主要是講Volley在某些細節方面的選擇和實現.值得我們學習的地方以及如果更好的使用Volley。

                                             

                                            1.Volley本地緩存為什麼有時候不會進行緩存?

                                            緩存使用前提服務器必須支持,緩存,配置Cache-Control頭信息,

                                            因為Volley需要從這些頭信息判斷緩存是否已經過期。如果已經過期Volley將會重新從網絡獲取數據。

                                            本人用抓包工具抓了無法緩存的返回頭信息

                                            \

                                            可以支持緩存的頭信息

                                            \

                                             

                                            2.如果我們自己寫一個網絡請求框架,我們內部實現會選擇使用HttpURLConnection還是HttpClient?

                                            我們通過源碼來看看Volley是如何選擇使用的

                                             

                                            [java]view plaincopy    
                                            1. publicstaticRequestQueuenewRequestQueue(Contextcontext,HttpStackstack){
                                            2. FilecacheDir=newFile(context.getCacheDir(),DEFAULT_CACHE_DIR);
                                            3. StringuserAgent="volley/0";
                                            4. try{
                                            5. StringpackageName=context.getPackageName();
                                            6. PackageInfoinfo=context.getPackageManager().getPackageInfo(packageName,0);
                                            7. userAgent=packageName+"/"+info.versionCode;
                                            8. }catch(NameNotFoundExceptione){
                                            9. }
                                            10. if(stack==null){
                                            11. if(Build.VERSION.SDK_INT>=9){
                                            12. stack=newHurlStack();
                                            13. }else{
                                            14. stack=newHttpClientStack(AndroidHttpClient.newInstance(userAgent));
                                            15. }
                                            16. }
                                            17. Networknetwork=newBasicNetwork(stack);
                                            18. RequestQueuequeue=newRequestQueue(newDiskBasedCache(cacheDir),network);
                                            19. queue.start();
                                            20. returnqueue;
                                            21. } 這裡會判斷如果手機系統版本號是大於9(Android 2.3)的,則創建一個HurlStack的實例,否則就創建一個HttpClientStack的實例。實際上HurlStack的內部就是使用HttpURLConnection進行網絡通訊的,而HttpClientStack的內部則是使用HttpClient進行網絡通訊的,這裡為什麼這樣選擇呢?參考文章:Android訪問網絡,使用HttpURLConnection還是HttpClient?這就是它為何這麼快的原因。

                                               

                                              從這點我們可以學習到,要針對不同SDK版本做去相應更優的處理方式,這樣才能達到最好的效果。

                                               

                                              3.Volley給我們提供了ImageRrequest,ImageLoader,NetworkImageView,它們分別使用於什麼場景為什麼?

                                              單張圖片的加載可以通過發起 ImageReuqst 請求來實現,但為了應用內存緩存,推薦使用ImageLoader

                                              NetwoekImageView專門用於批量圖片加載的場景:

                                               

                                              [java]view plaincopy    
                                              1. publicclassNetworkImageViewextendsImageView{
                                              2. privateStringmUrl;
                                              3.  
                                              4. //默認顯示的圖片
                                              5. privateintmDefaultImageId;
                                              6.  
                                              7. //加載失敗時顯示的圖片
                                              8. privateintmErrorImageId;
                                              9.  
                                              10. //主方法入口
                                              11. publicvoidsetImageUrl(Stringurl,ImageLoaderimageLoader){
                                              12. mUrl=url;
                                              13. mImageLoader=imageLoader;
                                              14. //這個方法將會對ImageView的尺寸是否有效、是否為同一張圖片進行判斷
                                              15. //在執行新請求前,也會取消上一次在這個View裡啟動的另一個已經失效的請求
                                              16. //由於篇幅的限制以及代碼行數太多,這裡不貼出具體實現的代碼
                                              17. loadImageIfNecessary(false);
                                              18. }
                                              19.  
                                              20. //如果圖片已經滑離屏幕,變為不可見,將執行取消請求的操作
                                              21. @Override
                                              22. protectedvoidonDetachedFromWindow(){
                                              23. if(mImageContainer!=null)mImageContainer.cancelRequest();
                                              24. super.onDetachedFromWindow();
                                              25. }
                                              26. } 在ListView加載多張圖片的時候,NetworkImageView可以防止出現圖片錯誤的現象,以及當NetworkImageView滑出屏幕的時候會取消加載圖片請求,這樣就保證加載多張圖片的時候用戶快速滑動列表的流暢性。給用戶帶來更優的體驗。
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved