多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > Android Volley框架完全解析

Android Volley框架完全解析

來源:程序員人生   發布時間:2016-11-17 09:42:38 閱讀次數:3070次

2013年Google I/O大會上推出了1個新的網絡通訊框架——Volley。Volley可是說是把AsyncHttpClient和Universal-Image-Loader的優點集于了1身,既可以像AsyncHttpClient1樣非常簡單地進行HTTP通訊,也能夠像Universal-Image-Loader1樣輕松加載網絡上的圖片。除簡單易用以外,Volley在性能方面也進行了大幅度的調劑,它的設計目標就是非常合適去進行數據量不大,但通訊頻繁的網絡操作,而對大數據量的網絡操作,比如說下載文件等,Volley的表現就會非常糟。

準備工作

導入JAR包(下載地址),申請網絡權限

<uses-permission android:name="android.permission.INTERNET" />

HTTP要求與響應

1. 使用StringRequest接收String類型的響應

1個最基本的HTTP要求與響應主要就是進行以下3步操作:

  • 創建1個RequestQueue對象。
  • 創建1個StringRequest對象(以StringRequest為例,后面還會介紹其他Request)。
  • 將StringRequest對象添加到RequestQueue里面。

(1)初始化要求隊列對象——RequestQueue

RequestQueue mQueue = Volley.newRequestQueue(context);

RequestQueue是1個要求隊列對象,它可以緩存所有的HTTP要求,然后依照1定的算法并發地發出這些要求。RequestQueue內部的設計就是非常適合高并發的,因此我們沒必要為每次HTTP要求都創建1個RequestQueue對象,這是非常浪費資源的。所以這里建議用單例模式定義這個對象。固然,你可以選擇在1個activity中定義1個RequestQueue對象,但這樣可能會比較麻煩,而且還可能出現要求隊列包括activity強援用的問題。

(2)使用StringRequest接收String類型的響應
前面定義了要求對象,那末自然就有接收響應的對象了,這個框架中有多個響應對象,像StringRequest接遭到的響應就是string類型的;JsonRequest接收的響應就是Json類型對象。其實它們都是繼承自Request<\T>,然后根據不同的響應數據來進行特殊的處理。
這里寫圖片描述

來看StringRequest的兩個構造函數

/** method:要求方法 url:要求的地址 listener:響應成功的監聽器 errorListener:出錯時的監聽器 **/ public StringRequest(int method, String url, Listenerlistener, ErrorListener errorListener) /**不傳入method,默許會調用GET方式進行要求**/ public StringRequest(String url, Listenerlistener, ErrorListener errorListener) { this(Method.GET, url, listener, errorListener); }

GET方式要求網絡,代碼以下:

StringRequest stringRequest = new StringRequest("http://www.baidu.com", new Response.Listener() { @Override public void onResponse(String response) { Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { showlog(error.getMessage()); } });

POST方式要求網絡,1般我們的POST都是要帶1些參數的,Volley沒有提供附加參數的方法,所以我們必須要在StringRequest的匿名類中重寫getParams()方法,代碼以下所示:

StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorListener) { @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("params1", "value1"); map.put("params2", "value2"); return map; } };

這樣就傳入了value1和value2兩個參數了。現在可能有人會問為啥這個框架不提供這個傳參的方法,還非得讓我們重寫。個人覺得這個框架本身的目的就是履行頻繁的網絡要求,比以下載圖片,解析json數據甚么的,用GET就可以很好的實現了,所以就沒有提供傳參的POST方法。

(3)發送要求
發送要求很簡單,將StringRequest對象添加到RequestQueue里面便可。

mQueue.add(stringRequest);

運行1下程序,發出1條HTTP要求,把服務器返回的string用Toast展現出來:
這里寫圖片描述
沒錯,百度返回給我們的就是這樣1長串的HTML代碼,雖然我們看起來會有些費勁,但是閱讀器卻可以輕松地對這段HTML代碼進行解析,然后將百度的首頁展現出來。

2. 使用JsonObjectRequest接收Json類型的響應

類似于StringRequest,JsonRequest也是繼承自Request類的,不過由于JsonRequest是1個抽象類,因此我們沒法直接創建它的實例,那末只能從它的子類入手了。JsonRequest有兩個直接的子類,JsonObjectRequest和JsonArrayRequest,從名字上你應當能就看出它們的區分了吧?1個是用于要求1段JSON數據的,1個是用于要求1段JSON數組的。
這里看1下JsonObjectRequest的構造函數:

//jsonRequest:POST要求攜帶的參數,可以為空,表示不攜帶參數 public JsonObjectRequest(int method, String url, JSONObject jsonRequest, Listenerlistener, ErrorListener errorListener) { super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, errorListener); } //如果jsonRequest為空,默許使用GET要求,否則使用POST public JsonObjectRequest(String url, JSONObject jsonRequest, Listenerlistener, ErrorListener errorListener) { this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest, listener, errorListener); }

和StringRequest1樣,遵守3步走原則:

RequestQueue mQueue = Volley.newRequestQueue(context); JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("http://weather.51wnl.com/weatherinfo/GetMoreWeather?cityCode=101020100&weatherType=0", null, new Response.Listener() { @Override public void onResponse(JSONObject response) { Toast.makeText(MainActivity.this, response.toString(), Toast.LENGTH_SHORT).show(); try { response = response.getJSONObject("weatherinfo"); showlog("city = " + response.getString("city")); showlog("weather1 = " + response.getString("weather1")); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { showlog(error.getMessage()); } }); mQueue.add(jsonObjectRequest);

注意JsonObjectRequest的POST方式攜帶參數和StringRequest有些不同,上面StringRequest的方式在這里不起作用。需要下面方式實現:

Map<String, String> params = new HashMap<String, String>(); params.put("name1", "value1"); params.put("name2", "value2"); JSONObject jsonRequest= new JSONObject(params); JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Method.POST, url, jsonRequest, listener, errorListener)

上面我們要求的地址是中央天氣預報的上海天氣,看1下運行效果:
這里寫圖片描述
可以看出,服務器返回給我們的數據確切是JSON格式的,并且onResponse()方法中攜帶的參數也正是1個JSONObject對象,以后只需要從JSONObject對象取出我們想要得到的那部份數據就能夠了。
這里寫圖片描述

3. 使用ImageRequest來要求圖片

首先來看1下ImageRequest的構造函數

public ImageRequest(String url, Response.Listenerlistener, int maxWidth, int maxHeight, Config decodeConfig, Response.ErrorListener errorListener) { super(Method.GET, url, errorListener); setRetryPolicy(new DefaultRetryPolicy(IMAGE_TIMEOUT_MS, IMAGE_MAX_RETRIES, IMAGE_BACKOFF_MULT)); mListener = listener; mDecodeConfig = decodeConfig; mMaxWidth = maxWidth; mMaxHeight = maxHeight; }

默許的要求方式是GET,初始化方法需要傳入:圖片的url,1個響應結果監聽器,圖片的最大寬度,圖片的最大高度,圖片的色彩屬性,出錯響應的監聽器。
第3第4個參數分別用于指定允許圖片最大的寬度和高度,如果指定的網絡圖片的寬度或高度大于這里的最大值,則會對圖片“等比例”進行緊縮,指定成0的話就表示不管圖片有多大,都不會進行緊縮。第5個參數用于指定圖片的色彩屬性,Bitmap.Config下的幾個常量都可以在這里使用,其中ARGB_8888可以展現最好的色彩屬性,每一個圖片像素占據4個字節的大小,而RGB_565則表示每一個圖片像素占據2個字節大小。
3步走開始:

RequestQueue mQueue = Volley.newRequestQueue(context); ImageRequest imageRequest = new ImageRequest( "/upload/images/2016/11/17/20161117582d0ed590f56.jpg", new Response.Listener() { @Override public void onResponse(Bitmap response) { image.setImageBitmap(response); } }, 0, 0, Config.RGB_565, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { image.setImageResource(R.drawable.default_image); } }); mQueue.add(imageRequest);

看運行效果圖:
這里寫圖片描述

加載圖片— ImageLoader & NetworkImageView

Volley有無其他的,更好的方式來獲得圖片呢?固然有的,比如ImageLoader、NetworkImageView這樣的對象,它們可以更加方便的獲得圖片。值得1提的是這兩個對象的內部都是使用了ImageRequest進行操作的,也就是說ImageRequest是本質。

1. ImageLoader加載圖片

ImageLoader也能夠用于加載網絡上的圖片,不過ImageLoader明顯要比ImageRequest更加高效,由于它不但可以幫我們對圖片進行緩存,還可以過濾掉重復的鏈接,避免重復發送要求。
由于ImageLoader已不是繼承自Request的了,所以它的用法也和我們之前學到的內容有所不同,總結起來大致可以分為以下4步:

  • 創建1個RequestQueue對象。
  • 創建1個ImageLoader對象。
  • 獲得1個ImageListener對象。
  • 調用ImageLoader的get()方法加載網絡上的圖片。

(1)創建1個RequestQueue對象
我們前面已寫過很多遍了,不再重復介紹了

(2)創建1個ImageLoader對象
示例代碼以下所示:

ImageLoader imageLoader = new ImageLoader(mQueue, new ImageCache() { @Override public void putBitmap(String url, Bitmap bitmap) { } @Override public Bitmap getBitmap(String url) { return null; } });

可以看到,ImageLoader的構造函數接收兩個參數,第1個參數就是RequestQueue對象,第2個參數是1個ImageCache對象(不能傳null!),這里的ImageCache就是為我們做內存緩存用的,我們可以定制自己的實現方式,現在主流的實現是LruCache,關于LruCache可以參考我之前寫的1篇文章Android的緩存技術:LruCache和DiskLruCache。

ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache());
//BitmapCache的實現類 public class BitmapCache implements ImageCache { private LruCache mCache; public BitmapCache() { int maxSize = 10 * 1024 * 1024; mCache = new LruCache(maxSize) { @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } }; @Override public Bitmap getBitmap(String url) { return mCache.get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { mCache.put(url, bitmap); } }

(3)獲得1個ImageListener對象

ImageListener listener = ImageLoader.getImageListener(imageView, R.drawable.default_image, R.drawable.fail_image);

我們通過調用ImageLoader的getImageListener()方法能夠獲得到1個ImageListener對象,getImageListener()方法接收3個參數,第1個參數指定用于顯示圖片的ImageView控件,第2個參數指定加載圖片的進程中顯示的圖片,第3個參數指定加載圖片失敗的情況下顯示的圖片。

(4)調用ImageLoader的get()方法加載網絡上的圖片

imageLoader.get("/upload/images/2016/11/17/20161117582d0ed5e4e1c.jpg", listener);

get()方法接收兩個參數,第1個參數就是圖片的URL地址,第2個參數則是剛剛獲得到的ImageListener對象。固然,如果你想對圖片的大小進行限制,也能夠使用get()方法的重載,指定圖片允許的最大寬度和高度,以下所示:

imageLoader.get("/upload/images/2016/11/17/20161117582d0ed5e4e1c.jpg", listener, 600, 600);

運行1下程序點擊加載圖片,你將看到ImageView會先顯示1張默許的加載進程中圖片,等到網絡上的圖片加載完成后,ImageView則會自動顯示該圖。如果我們用ImageLoader再次加載該圖片,會很快顯示出來而看不到默許的加載進程中圖片,這是由于這次的圖片是從緩存中取的,速度很快。效果以下圖所示。
這里寫圖片描述

注:上面我們只是定制了內存緩存,查看源碼,可以發現ImageLoader對圖片也進行了硬盤緩存,我們在履行get()方法前可以通過imageLoader.setShouldCache(false);來取消硬盤緩存,如果你不進行設置的話默許是履行硬盤緩存的。看看控制硬盤緩存的幾個方法:

public final boolean shouldCache() //查看是不是已做了磁盤緩存。 void setShouldCache(boolean shouldCache)//設置是不是運行磁盤緩存,此方法需要在get方法前使用 public boolean isCached(String requestUrl, int maxWidth, int maxHeight)//判斷對象是不是已被緩存,傳入url,還有圖片的最大寬高

2. NetworkImageView加載圖片

NetworkImageView繼承自ImageView,你可以認為它是1個可以實現加載網絡圖片的imageview,10分簡單好用。這個控件在被從父控件分離的時候,會自動取消網絡要求的,即完全不用我們擔心相干網絡要求的生命周期問題。
NetworkImageView控件的用法大致可以分為以下5步:

  • 創建1個RequestQueue對象。
  • 創建1個ImageLoader對象。
  • 在布局文件中添加1個NetworkImageView控件。
  • 在代碼中獲得該控件的實例。
  • 設置要加載的圖片地址。
<com.android.volley.toolbox.NetworkImageView android:id="@+id/network_image_view" android:layout_width="200dp" android:layout_height="200dp" android:layout_gravity="center_horizontal" />
/**創建RequestQueue和ImageLoader對象**/ RequestQueue mQueue = Volley.newRequestQueue(context); ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache()); /**獲得NetworkImageView控件**/ NetworkImageView networkImageView = (NetworkImageView) findViewById(R.id.network_image_view); /**設置加載中顯示的圖片**/ networkImageView.setDefaultImageResId(R.drawable.default_image); /**加載失敗時顯示的圖片**/ networkImageView.setErrorImageResId(R.drawable.fail_image); /**設置目標圖片的URL地址**/ networkImageView.setImageUrl("/upload/images/2016/11/17/20161117582d0ed65b8d8.jpg", imageLoader);

好了,就是這么簡單,現在重新運行1下程序,你將看到和使用ImageLoader來加載圖片1模1樣的效果,這里我就不再截圖了。
NetworkImageView沒有提供任何設置圖片寬高的方法,這是由于它是1個控件,在加載圖片的時候它會自動獲得本身的寬高,然后對照網絡圖片的寬度,再決定是不是需要對圖片進行緊縮。也就是說,緊縮進程是在內部完全自動化的,其實不需要我們關心。NetworkImageView終究會始終顯現給我們1張大小比控件尺寸略大的網絡圖片,由于它會根據控件寬高來等比縮放原始圖片,不會多占用任何1點內存,這也是NetworkImageView最簡單好用的1點吧。
如果你不想對圖片進行緊縮的話,只需要在布局文件中把NetworkImageView的layout_width和layout_height都設置成wrap_content就能夠了,這樣它就會將該圖片的原始大小展現出來,不會進行任何緊縮。

自定義Request

Volley中提供了幾個經常使用Request(StringRequest、JsonObjectRequest、JsonArrayRequest、ImageRequest),如果我們有自己特殊的需求,其實完全可以自定義自己的Request。
自定義Request之前,我們先來看看StringRequest的源碼實現:

package com.android.volley.toolbox; public class StringRequest extends Request<String> { // 建立監聽器來取得響應成功時返回的結果 private final ListenermListener; // 傳入要求方法,url,成功時的監聽器,失敗時的監聽器 public StringRequest(int method, String url, Listenerlistener, ErrorListener errorListener) { super(method, url, errorListener); // 初始化成功時的監聽器 mListener = listener; } /** * Creates a new GET request. * 建立1個默許的GET要求,調用了上面的構造函數 */ public StringRequest(String url, Listenerlistener, ErrorListener errorListener) { this(Method.GET, url, listener, errorListener); } @Override protected void deliverResponse(String response) { // 用監聽器的方法來傳遞下響應的結果 mListener.onResponse(response); } @Override protected ResponseparseNetworkResponse(NetworkResponse response) { String parsed; try { // 調用了new String(byte[] data, String charsetName) 這個構造函數來構建String對象,將byte數組依照特定的編碼方式轉換為String對象,主要部份是data parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException e) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); } }

首先StringRequest是繼承自Request類的,Request可以指定1個泛型類,這里指定確當然就是String了,接下來StringRequest中提供了兩個有參的構造函數,參數包括要求類型,要求地址,和響應回調等。但需要注意的是,在構造函數中1定要調用super()方法將這幾個參數傳給父類,由于HTTP的要求和響應都是在父類中自動處理的。
另外,由于Request類中的deliverResponse()和parseNetworkResponse()是兩個抽象方法,因此StringRequest中需要對這兩個方法進行實現。deliverResponse()方法中的實現很簡單,僅僅是調用了mListener中的onResponse()方法,并將response內容傳入便可,這樣就能夠將服務器響應的數據進行回調了。parseNetworkResponse()方法中則是對服務器響應的數據進行解析,其中數據是以字節的情勢寄存在NetworkResponse的data變量中的,這里將數據取出然后組裝成1個String,并傳入Response的success()方法中便可。

1. 自定義XMLRequest

了解了StringRequest的實現原理,下面我們就能夠動手來嘗試實現1下XMLRequest了,代碼以下所示:

public class XMLRequest extends Request<XmlPullParser> { private final ListenermListener; public XMLRequest(int method, String url, Listenerlistener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } public XMLRequest(String url, Listenerlistener, ErrorListener errorListener) { this(Method.GET, url, listener, errorListener); } @Override protected ResponseparseNetworkResponse(NetworkResponse response) { try { String xmlString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser xmlPullParser = factory.newPullParser(); xmlPullParser.setInput(new StringReader(xmlString)); return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (XmlPullParserException e) { return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(XmlPullParser response) { mListener.onResponse(response); } }

可以看到,其實并沒有甚么太多的邏輯,基本都是仿照StringRequest寫下來的,XMLRequest也是繼承自Request類的,只不過這里指定的泛型類是XmlPullParser,說明我們準備使用Pull解析的方式來解析XML。在parseNetworkResponse()方法中,先是將服務器響應的數據解析成1個字符串,然后設置到XmlPullParser對象中,在deliverResponse()方法中則是將XmlPullParser對象進行回調。
下面我們嘗試使用這個XMLRequest來要求1段XML格式的數據,http://flash.weather.com.cn/wmaps/xml/china.xml這個接口會將中國所有的省分數據以XML格式進行返回,以下所示:
這里寫圖片描述

XMLRequest xmlRequest = new XMLRequest("http://flash.weather.com.cn/wmaps/xml/china.xml", new Response.Listener() { @Override public void onResponse(XmlPullParser response) { try { int eventType = response.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_TAG: String nodeName = response.getName(); if ("city".equals(nodeName)) { String pName = response.getAttributeValue(0); String cName = response.getAttributeValue(2); showlog("省分:" + pName + " 城市:" + cName); } break; } eventType = response.next(); } } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { showlog(error.getMessage()); } }); mQueue.add(xmlRequest);

這里寫圖片描述

2. 自定義GsonRequest

JsonRequest的數據解析是利用Android本身自帶的JSONObject和JSONArray來實現的,配合使用JSONObject和JSONArray就能夠解析出任意格式的JSON數據。不過或許你會覺得使用JSONObject還是太麻煩了,還有很多方法可讓JSON數據解析變得更加簡單,比如說GSON對象。遺憾的是,Volley中默許其實不支持使用自家的GSON來解析數據,不過沒有關系,通過上面的學習,相信你已知道了自定義1個Request是多么的簡單,那末下面我們就來舉1反31下,自定義1個GsonRequest。
首先我們需要把GSON的jar包導入到項目當中,接著定義1個GsonRequest繼承自Request,代碼以下所示:

public class GsonRequestextends Request{ private final ListenermListener; private Gson mGson; private ClassmClass; public GsonRequest(int method, String url, Classclazz, Listenerlistener, ErrorListener errorListener) { super(method, url, errorListener); mGson = new Gson(); mClass = clazz; mListener = listener; } public GsonRequest(String url, Classclazz, Listenerlistener, ErrorListener errorListener) { this(Method.GET, url, clazz, listener, errorListener); } @Override protected ResponseparseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success(mGson.fromJson(jsonString, mClass), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(T response) { mListener.onResponse(response); } }

GsonRequest是繼承自Request類的,并且一樣提供了兩個構造函數。在parseNetworkResponse()方法中,先是將服務器響應的數據解析出來,然后通過調用Gson的fromJson方法將數據組裝成對象。在deliverResponse方法中依然是將終究的數據進行回調。
下面我們就來測試1下這個GsonRequest能不能夠正常工作吧,一樣調用http://www.weather.com.cn/data/sk/101020100.html這個接口可以得到1段JSON格式的天氣數據,以下所示:

{"weatherinfo":{"city":"上海","city_en":"","cityid":101020100,"date":"","date_y":"2016年09月20日","fchh":0,"fl1":"","fl2":"","fl3":"","fl4":"","fl5":"","fl6":"","fx1":"","fx2":"","img1":"1","img10":"1","img11":"1","img12":"1","img2":"1","img3":"1","img4":"1","img5":"1","img6":"1","img7":"1","img8":"1","img9":"1","img_single":0,"img_title1":"","img_title10":"","img_title11":"","img_title12":"","img_title2":"","img_title3":"","img_title4":"","img_title5":"","img_title6":"","img_title7":"","img_title8":"","img_title9":"","img_title_single":"","index":"","index48":"","index48_d":"","index48_uv":"","index_ag":"","index_cl":"","index_co":"","index_d":"","index_ls":"","index_tr":"","index_uv":"","index_xc":"","st1":0,"st2":0,"st3":0,"st4":0,"st5":0,"st6":0,"temp1":"20℃~28℃","temp2":"20℃~26℃","temp3":"19℃~26℃","temp4":"21℃~26℃","temp5":"23℃~28℃","temp6":"22℃~27℃","tempF1":"","tempF2":"","tempF3":"","tempF4":"","tempF5":"","tempF6":"","weather1":"多云","weather2":"多云","weather3":"多云","weather4":"多云","weather5":"多云","weather6":"多云","week":"","wind1":"","wind2":"","wind3":"","wind4":"","wind5":"","wind6":""}}

我們需要使用對象的方式將這段JSON字符串表示出來。下面新建兩個Bean文件:

public class Weather { public WeatherInfo weatherinfo; }
public class WeatherInfo { public String city; public String cityid; public String date_y; public String temp1; public String weather1; }

下面就是用GsonRequest要求json數據了

GsonRequestgsonRequest = new GsonRequest( "http://weather.51wnl.com/weatherinfo/GetMoreWeather?cityCode=101020100&weatherType=0", Weather.class, new Response.Listener() { @Override public void onResponse(Weather weather) { WeatherInfo weatherInfo = weather.weatherinfo; showlog("city is " + weatherInfo.city); showlog("cityid is " + weatherInfo.cityid); showlog("date_y is " + weatherInfo.date_y); showlog("temp1 is " + weatherInfo.temp1); showlog("weather1 is " + weatherInfo.weather1); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { showlog(error.getMessage()); } }); mQueue.add(gsonRequest);

這里onResponse()方法的回調中直接返回了1個Weather對象,我們通過它就能夠得到WeatherInfo對象,接著就可以從中取出JSON中的相干數據了。運行1下程序,打印Log以下:
這里寫圖片描述

3. 自定義GsonRequestWithAuth

上面自定義的Request并沒有攜帶參數,如果我們訪問服務器時需要傳參呢?比方通過客戶端訪問服務器服務器對客戶端進行身份校驗后,返回用戶信息,客戶端直接拿到對象。
先寫Bean文件:

public class User { private String name; private int age; }

自定義GsonRequestWithAuth:

public class GsonRequestWithAuth<T> extends Request<T> { private final Gson gson = new Gson(); private final Classclazz; private final Listenerlistener; private Map mHeader = new HashMap(); private String mBody; /** http要求編碼方式 */ private static final String PROTOCOL_CHARSET = "utf⑻"; /** 設置訪問自己服務器時必須傳遞的參數,密鑰等 */ static { mHeader.put("APP-Key", "Key"); mHeader.put("APP-Secret", "Secret"); } /** * @param url * @param clazz 我們終究的轉化類型 * @param listener * @param appendHeader 附加頭數據 * @param body 要求附帶消息體 * @param errorListener */ public GsonRequestWithAuth(String url, Classclazz, Listenerlistener, Map appendHeader, String body, ErrorListener errorListener) { super(Method.POST, url, errorListener); this.clazz = clazz; this.listener = listener; mHeader.putAll(appendHeader); mBody = body; } @Override public Map getHeaders() throws AuthFailureError { // 默許返回 return Collections.emptyMap(); return mHeader; } @Override public byte[] getBody() { try { return mBody == null ? null : mBody.getBytes(PROTOCOL_CHARSET); } catch (UnsupportedEncodingException uee) { VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", mUserName, PROTOCOL_CHARSET); return null; } } @Override protected void deliverResponse(T response) { listener.onResponse(response); } @Override protected ResponseparseNetworkResponse(NetworkResponse response) { try { /** 得到返回的數據 */ String jsonStr = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); /** 轉化成對象 */ return Response.success(gson.fromJson(jsonStr, clazz), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JsonSyntaxException e) { return Response.error(new ParseError(e)); } } }

服務器代碼:

public class TestServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf⑻"); /**獲得APP-Key和APP-Secret */ String appKey = request.getHeader("APP-Key"); String appSecret = request.getHeader("APP-Secret"); /**獲得用戶名、密碼 */ String username = request.getHeader("username"); String password = request.getHeader("password"); /**獲得消息體 */ int size = request.getContentLength(); InputStream is = request.getInputStream(); byte[] reqBodyBytes = readBytes(is, size); String body = new String(reqBodyBytes); if ("admin".equals(username) && "123".equals(password) && "getUserInfo".equals(body)) { response.setContentType("text/plain;charset=utf⑻"); PrintWriter out = response.getWriter(); out.print("{\"name\":\"Watson\",\"age\":28}"); out.flush(); } } }

使用GsonRequestWithAuth和服務器交互要求信息:

Map<String, String> appendHeader = new HashMap<String, String>(); appendHeader.put("username", "admin"); appendHeader.put("password", "123"); String url = "http://172.27.35.1:8080/webTest/TestServlet"; GsonRequestWithAuthuserRequest = new GsonRequestWithAuth(url, User.class, new Listener() { @Override public void onResponse(User response) { Log.e("TAG", response.toString()); } }, appendHeader, "getUserInfo", null); mQueue.add(userRequest);

延伸:
看到沒有,我們上面寫服務器端代碼時,有1句代碼是設置服務器返回數據的字符集為UTF⑻

response.setContentType("text/plain;charset=utf⑻");

大部份服務器端都會在返回數據的header中指定字符集,如果在服務器端沒有指定字符集那末就會默許使用 ISO⑻859⑴ 字符集。
ISO⑻859⑴的別名叫做Latin1。這個字符集支持部份是用于歐洲的語言,不支持中文,這就會致使服務器返回的中文數據亂碼,很不能理解為何將這個字符集作為默許的字符集。Volley這個框架可是要用在網絡通訊的環境中的。吐槽也沒有用,我們來看1下如何來解決中文亂碼的問題。有以下幾種解決方式:

  • 服務器的返回的數據的header的中contentType加上charset=UTF⑻的聲明。
  • 當你沒法修改服務器程序的時候,可以定義1個新的子類。覆蓋parseNetworkResponse這個方法,直接使用UTF⑻對服務器的返回數據進行轉碼。
public class CharsetStringRequest extends StringRequest { public CharsetStringRequest(String url, Listenerlistener, ErrorListener errorListener) { super(url, listener, errorListener); } public CharsetStringRequest(int method, String url, Listenerlistener, ErrorListener errorListener) {
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 白浆都出来了视频国产精品 | 手机看片福利视频 | 亚洲国产精品日韩一线满 | 五月天开心中文字幕 | 欧美激情一区二区 | 天堂俺去俺来也www久久婷婷 | 久久精品国产国语对白 | jiuse在线| 伊人久久免费视频 | 亚洲日本视频在线观看 | 亚洲欧美小说图片 | xxxxxx日本| 亚洲蜜桃| 欧美视频一区在线 | 日本天堂网址 | 欧美深夜在线 | 中文字幕在线播 | 精品一区二区三区四区乱码 | 国产精品第一页第一页 | 啦啦啦啦高清视频免费观看 | 波多野结衣视频免费在线观看 | 日本特黄a级高清免费酷网 日本特黄的免费大片视频 日本特黄高清免费大片爽 日本特黄色大片 | 久久国产一久久高清 | 黑人最猛性free护士hd | 国产三级在线观看播放 | 日本另类图片 | 在线看欧美成人中文字幕视频 | 欧美重口另类videos人妖 | 综合精品一区 | 色综合免费视频 | 日韩欧美一区二区精品久久 | 最近中文字幕资源8 | 性欧美xxxx性 | 精品番号 | 亚洲久久色 | 精品72久久久久久久中文字幕 | 日韩有码在线视频 | 现代激情校园春色 | 国产精品久久久久久爽爽爽 | 日本理论在线观看被窝网 | 永久在线观看www免费视频 |