<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                從前在學校用的最多的網絡請求框架就是AsyncHttpClient,用久了發現這樣一個問題,就是代碼復用太難,基本上做不到,所以有一段時間又回歸了HttpURLConnection和HttpClient,再后來又學習了OKHttp的使用,雖然這幾種網絡請求各有各的優勢,但是原理基本上都是一樣的,在android6.0中Google已經不提供HttpClient的API了,所以從長遠的角度來考慮,推薦大家多用OKHttp,關于OKHttp的使用可以參見[OKHttp的簡單使用](http://blog.csdn.net/u012702547/article/details/49045765)。除了上面說的這幾種通信方式,Google在2013年(好早呀![尷尬](https://box.kancloud.cn/2016-04-08_57075946dd94c.gif) )的I/O大會上還推出了一個網絡請求框架Volley,這和AsyncHttpClient的使用非常像,之前一直沒有總結過Volley的使用,周末有時間總結一下,與大家分享。 Volley適用于交互頻繁但是數據量小的網絡請求,比如我們在上一篇博客中介紹的新聞列表,這種情況下使用Volley就是非常合適的,但是對于一些數據量大的網絡請求,比如下載,Volley就顯得略有力不從心。 Volley是一個開源項目,我們可以在GitHub上獲得它的源代碼,地址[https://github.com/mcxiaoke/android-volley](https://github.com/mcxiaoke/android-volley),拿到之后我們可以將之打包成jar包使用,也可以直接將源碼拷貝到我們的項目中使用,個人推薦第二種方式,這樣發生錯誤的時候方便我們調試,同時也有利于我們修改源碼,定制我們自己的Volley。如果要拷貝源碼,我們只需要將“android-volley-master\android-volley-master\src\main\java”這個文件夾下的com包拷貝到我們的項目中即可。 # 1.請求字符數據 Volley的使用,我們要先獲得一個隊列,我們的所有請求將會放在這個隊列中一個一個執行: ~~~ RequestQueue mQueue = Volley.newRequestQueue(this); ~~~ 獲得一個請求隊列只需要一個參數,就是Context,這里因為在MainActivity發起請求,所以直接用this。字符型數據的請求,我們使用StringRequest: ~~~ StringRequest sr = new StringRequest("http://www.baidu.com", new Response.Listener<String>() { @Override public void onResponse(String response) { Log.i("lenve", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); ~~~ StringRequest一共需要三個參數,第一個是我們要請求的http地址,第二個是數據調用成功的回調函數,第三個參數是數據調用失敗的回調函數。我們可以在回調函數中直接更新UI,Volley的這個特點和AsyncHttpClient還是非常相似的,關于這里邊的原理我們后邊有時間可以詳細介紹。獲得一個StringRequest對象的實例之后,我們把它添加到隊列之中,這樣就可以請求到網絡數據了: ~~~ mQueue.add(sr); ~~~ 嗯,就是這么簡單。那我們不禁有疑問了,剛才這個請求時get請求還是post請求?我們如何自己設置網絡請求方式?我們看一下這個構造方法的源碼: ~~~ /** * Creates a new GET request. * * @param url URL to fetch the string at * @param listener Listener to receive the String response * @param errorListener Error listener, or null to ignore errors */ public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) { this(Method.GET, url, listener, errorListener); } ~~~ 原來這個構造方法調用了另外一個構造方法,并且第一個參數傳遞了Method.GET,也就是說上面的請求其實是一個GET請求,那么我們如果要使用POST請求就直接通過下面這個構造方法來實現就可以了: ~~~ /** * Creates a new request with the given method. * * @param method the request {@link Method} to use * @param url URL to fetch the string at * @param listener Listener to receive the String response * @param errorListener Error listener, or null to ignore errors */ public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } ~~~ 那么使用了POST請求之后我們該怎么樣來傳遞參數呢?我們看到StringRequest中并沒有類似的方法來讓我們完成工作,但是StringRequest繼承自Request,我們看看Request中有沒有,很幸運,我們找到了: ~~~ /** * Returns a Map of parameters to be used for a POST or PUT request. Can throw * {@link AuthFailureError} as authentication may be required to provide these values. * * <p>Note that you can directly override {@link #getBody()} for custom data.</p> * * @throws AuthFailureError in the event of auth failure */ protected Map<String, String> getParams() throws AuthFailureError { return null; } ~~~ 看注釋我們大概就明白這個方法是干什么的了,它將POST請求或者PUT請求需要的參數封裝成一個Map對象,那么我們如果在POST請求中需要傳參的話,直接重寫這個方法就可以了,代碼如下: ~~~ StringRequest sr = new StringRequest("http://www.baidu.com", new Response.Listener<String>() { @Override public void onResponse(String response) { Log.i("lenve", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }) { /** * 重寫getParams(),可以自己組裝post要提交的參數 */ @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("params1", "value1"); map.put("params1", "value1"); return map; } }; ~~~ 好了,請求字符數據就是這么簡單。 # 2.請求JSON數據 關于json數據的請求,Volley已經給我們提供了相關的類了: ~~~ JsonObjectRequest jsonReq = new JsonObjectRequest(HTTPURL, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { try { JSONObject jo = response.getJSONObject("paramz"); JSONArray ja = jo.getJSONArray("feeds"); for (int i = 0; i < ja.length(); i++) { JSONObject jo1 = ja.getJSONObject(i) .getJSONObject("data"); Log.i("lenve", jo1.getString("subject")); } } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); mQueue.add(jsonReq); ~~~ 我們看看打印出來的結果: ![](https://box.kancloud.cn/2016-04-08_57075946ede2b.jpg) OK,沒問題,就是這么簡單,以此類推,你應該也就會使用JSONArray了。 # 3.使用ImageLoader加載圖片 Volley提供的另外一個非常好用的工具就是ImageLoader,這個網絡請求圖片的工具類,帶給我們許多方便,首先它會自動幫助我們把圖片緩存在本地,如果本地有圖片,它就不會從網絡獲取圖片,如果本地沒有緩存圖片,它就會從網絡獲取圖片,同時如果本地緩存的數據超過我們設置的最大緩存界限,它會自動移除我們在最近用的比較少的圖片。我們看一下代碼: ~~~ ImageLoader il = new ImageLoader(mQueue, new BitmapCache()); ImageListener listener = ImageLoader.getImageListener(iv, R.drawable.ic_launcher, R.drawable.ic_launcher); il.get(IMAGEURL, listener); ~~~ 先實例化一個ImageLoader,實例化ImageLoader需要兩個參數,第一個就是我們前文說的網絡請求隊列,第二個參數就是一個圖片緩存類,這個類要我們自己來實現,其實只需要實現ImageCache接口就可以了,里面具體的緩存邏輯由我們自己定義,我們使用Google提供的LruCache來實現圖片的緩存。然后就是我們需要一個listener,獲得這個listener需要三個參數,第一個是我們要加載網絡圖片的ImageView,第二個參數是默認圖片,第三個參數是加載失敗時候顯示的圖片。最后通過get方法來實現圖片的加載,通過源碼追蹤我們發現這個get方法會來到這樣一個方法中: ~~~ public ImageContainer get(String requestUrl, ImageListener imageListener, int maxWidth, int maxHeight, ScaleType scaleType) { // only fulfill requests that were initiated from the main thread. throwIfNotOnMainThread(); final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType); // Try to look up the request in the cache of remote images. Bitmap cachedBitmap = mCache.getBitmap(cacheKey); if (cachedBitmap != null) { // Return the cached bitmap. ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null); imageListener.onResponse(container, true); return container; } // The bitmap did not exist in the cache, fetch it! ImageContainer imageContainer = new ImageContainer(null, requestUrl, cacheKey, imageListener); // Update the caller to let them know that they should use the default bitmap. imageListener.onResponse(imageContainer, true); // Check to see if a request is already in-flight. BatchedImageRequest request = mInFlightRequests.get(cacheKey); if (request != null) { // If it is, add this request to the list of listeners. request.addContainer(imageContainer); return imageContainer; } // The request is not already in flight. Send the new request to the network and // track it. Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType, cacheKey); mRequestQueue.add(newRequest); mInFlightRequests.put(cacheKey, new BatchedImageRequest(newRequest, imageContainer)); return imageContainer; } ~~~ 我們看到在這個方法中會先判斷本地緩存中是否有我們需要的圖片,如果有的話直接從本地加載,沒有才會請求網絡數據,這正是使用ImageLoader的方便之處。 # 4.使用NetworkImageView加載網絡圖片 NetworkImageView和前面說的ImageLoader其實非常相像,不同的是如果使用NetworkImageView的話,我們的控件就不是ImageView了,而是NetworkImageView,我們看看布局文件: ~~~ <com.android.volley.toolbox.NetworkImageView android:id="@+id/iv2" android:layout_width="wrap_content" android:layout_height="wrap_content"/> ~~~ 在MainActivity中拿到它: ~~~ NetworkImageView niv = (NetworkImageView) this.findViewById(R.id.iv2); ~~~ 設置網絡請求參數: ~~~ niv.setDefaultImageResId(R.drawable.ic_launcher); ImageLoader il = new ImageLoader(mQueue, new BitmapCache()); niv.setImageUrl(IMAGEURL, il); ~~~ 首先設置默認圖片,然后是一個ImageLoader,這個ImageLoader和前文說的一模一樣,最后就是設置請求圖片的URL地址和一個ImageLoader,我們基本可以判斷NetworkImageView也會自動幫我們處理圖片的緩存問題。事實上的確如此,我們通過追蹤setImageUrl這個方法的源碼,發現它最終也會執行到我們在上面貼出來的那個方法中: ~~~ public ImageContainer get(String requestUrl, ImageListener imageListener, int maxWidth, int maxHeight, ScaleType scaleType) { .... } ~~~ 沒錯,NetworkImageView和ImageLoader最終都會到達這個方法,所以說這兩個東東其實非常像,那么在實際開發中究竟用哪個要視情況而定。 # 5.ImageRequest的使用 ImageRequest也是用來加載網絡圖片的,用法與請求字符串數據和請求json數據差不多: ~~~ ImageRequest ir = new ImageRequest(IMAGEURL, new Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { iv3.setImageBitmap(response); } }, 200, 200, ScaleType.CENTER, Bitmap.Config.ARGB_8888, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); mQueue.add(ir); ~~~ ImageRequest一共需要七個參數,第一個是要請求的圖片的IP地址,第二個請求成功的回調函數,第三個參數和第四個參數表示允許圖片的最大寬高,如果圖片的大小超出了設置會自動縮小,縮小方法依照第五個參數的設定,第三個和第四個參數如果設置為0則不會對圖片的大小做任何處理(原圖顯示),第六個參數表示繪圖的色彩模式,第七個參數是請求失敗時的回調函數。這個和前面兩種加載圖片的方式比較起來還是稍微有點麻煩。 # 6.定制自己的Request 上面介紹了Volley可以實現的幾種請求,但是畢竟還是比較有限,而我們在項目中遇到的情況可能是各種各樣的,比如服務端如果傳給我們的是一個XML數據,那么我們該怎樣使用Volley?Volley的強大之處除了上文我們說的之外,還在于它是開源的,我們可以根據自己的需要來定制Volley。那么我們就看看怎么定制XMLRequest,在定制已之前我們先看看JSONRequest是怎么實現的? ~~~ public class JsonObjectRequest extends JsonRequest<JSONObject> { /** * Creates a new request. * @param method the HTTP method to use * @param url URL to fetch the JSON from * @param requestBody A {@link String} to post with the request. Null is allowed and * indicates no parameters will be posted along with request. * @param listener Listener to receive the JSON response * @param errorListener Error listener, or null to ignore errors. */ public JsonObjectRequest(int method, String url, String requestBody, Listener<JSONObject> listener, ErrorListener errorListener) { super(method, url, requestBody, listener, errorListener); } /** * Creates a new request. * @param url URL to fetch the JSON from * @param listener Listener to receive the JSON response * @param errorListener Error listener, or null to ignore errors. */ public JsonObjectRequest(String url, Listener<JSONObject> listener, ErrorListener errorListener) { super(Method.GET, url, null, listener, errorListener); } /** * Creates a new request. * @param method the HTTP method to use * @param url URL to fetch the JSON from * @param listener Listener to receive the JSON response * @param errorListener Error listener, or null to ignore errors. */ public JsonObjectRequest(int method, String url, Listener<JSONObject> listener, ErrorListener errorListener) { super(method, url, null, listener, errorListener); } /** * Creates a new request. * @param method the HTTP method to use * @param url URL to fetch the JSON from * @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and * indicates no parameters will be posted along with request. * @param listener Listener to receive the JSON response * @param errorListener Error listener, or null to ignore errors. */ public JsonObjectRequest(int method, String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorListener) { super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, errorListener); } /** * Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is * <code>null</code>, <code>POST</code> otherwise. * * @see #JsonObjectRequest(int, String, JSONObject, Listener, ErrorListener) */ public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorListener) { this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest, listener, errorListener); } @Override protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)); return Response.success(new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JSONException je) { return Response.error(new ParseError(je)); } } } ~~~ 哈,原來這么簡單,光是構造方法就有五個,不過構造方法都很簡單,我們就不多說,核心的功能在parseNetworkResponse方法中,這里調用成功的時候返回一個Response泛型,泛型里邊的東西是一個JSONObject,其實也很簡單,我們如果要處理XML,那么直接在重寫parseNetworkResponse方法,在調用成功的時候直接返回一個Response泛型,這個泛型中是一個XmlPullParser對象,哈哈,很簡單吧,同時,結合StringRequest的實現方式,我們實現了XMLRequest的代碼: ~~~ public class XMLRequest extends Request<XmlPullParser> { private Listener<XmlPullParser> mListener; public XMLRequest(String url, Listener<XmlPullParser> mListener, ErrorListener listener) { this(Method.GET, url, mListener, listener); } public XMLRequest(int method, String url, Listener<XmlPullParser> mListener, ErrorListener listener) { super(method, url, listener); this.mListener = mListener; } @Override protected Response<XmlPullParser> parseNetworkResponse( NetworkResponse response) { String parsed; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser parser = factory.newPullParser(); parser.setInput(new StringReader(parsed)); return Response.success(parser, HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { parsed = new String(response.data); } catch (XmlPullParserException e) { e.printStackTrace(); } return null; } @Override protected void deliverResponse(XmlPullParser response) { if (mListener != null) { mListener.onResponse(response); } } @Override protected void onFinish() { super.onFinish(); mListener = null; } } ~~~ 就是這么簡單,在parseNetworkResponse方法中我們先拿到一個xml的字符串,再將這個字符串轉為一個XmlPullParser對象,最后返回一個Response泛型,這個泛型中是一個XmlPullParser對象。然后我們就可以使用這個XMLRequest了: ~~~ XMLRequest xr = new XMLRequest(XMLURL, new Response.Listener<XmlPullParser>() { @Override public void onResponse(XmlPullParser parser) { try { int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_DOCUMENT: break; case XmlPullParser.START_TAG: String tagName = parser.getName(); if ("city".equals(tagName)) { Log.i("lenve", new String(parser.nextText())); } break; case XmlPullParser.END_TAG: break; } eventType = parser.next(); } } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); mQueue.add(xr); ~~~ 用法和JSONRequest的用法一致。會自定義XMLRequest,那么照貓畫虎也可以自定義一個GsonRequest,各種各樣的數據類型我們都可以自己定制了。 好了,關于Volley的使用我們就介紹到這里,有問題歡迎留言討論。 [Demo下載https://github.com/lenve/VolleyDemo](https://github.com/lenve/VolleyDemo)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看