Android working with Volley

Volley是google官方推出的一個開源網絡訪問庫,在項目中直接使用它,而不須要寫一大堆的重複的代碼;html

項目主頁:android

https://android.googlesource.com/platform/frameworks/volleyjson

Volley中一個重要的類就是RequestQueue,不用多說,只看命名就知道它是一個請求隊列,用於存放咱們添加進去的網絡請求;緩存

咱們能夠經過Volley.newRequestQueue(Context context);獲取一個RequestQueue對象,一般一個應用程序中使用一個RequestQueue實例便可,所以能夠把RequestQueue實例存放在Application中,當作一個全局變量;網絡

下面直接經過例子來學習此開源庫的使用;app

1、字符串請求ide

    protected void stringRequest() {
        String url = "http://www.baidu.com";
        StringRequest sr = new StringRequest(Method.GET, url,
                new Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        Log.e(tag, "" + response);
                    }
                }, new ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                    }
                });
        sr.setTag("tag");
        reqQueue.add(sr);
    }

其中reqQueue即爲RequestQueue實例對象(同下文);
咱們只須要產生一個StringRequest實例,而後添加進RequestQueue隊列當中便可,在建立實例的時候,會分別設置請求成功和請求失敗時的監聽回調,在監聽器裏面咱們能夠作相應的處理;函數

2、Json請求學習

Json請求分別兩種,分別是JsonObjectRequest和JsonArrayRequest,下邊咱們來看一個JsonObjectRequest請求;fetch

    protected void jsonObjectRequest() {
        String url = "http://m.weather.com.cn/data/101010100.html";
        JsonObjectRequest jor = new JsonObjectRequest(Request.Method.GET, url,
                null, new Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        Log.e(tag, "" + response);
                    }
                }, new ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                    }
                });
        jor.setTag("tag");
        reqQueue.add(jor);
    }

和StringRequest相仿,再也不表述,同理JsonArrayRequest也是同樣;

3、圖片請求

    protected void imageRequest() {
        iv = (ImageView) findViewById(R.id.iv);
        String url = "http://img0.bdstatic.com/img/image/shouye/hjxnzz04.jpg";
        ImageRequest ir = new ImageRequest(url, new Listener<Bitmap>() {
            @Override
            public void onResponse(Bitmap response) {
                iv.setImageBitmap(response);
            }
        }, 0, 0, Config.RGB_565, new ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                iv.setImageResource(R.drawable.ic_launcher);
            }
        });
        ir.setTag("tag");
        reqQueue.add(ir);
        // ImageRequest的構造函數接收六個參數
        // url:圖片的URL地址
        // listener:圖片請求成功的回調
        // maxWidth:容許圖片最大的寬度,指定的網絡圖片的寬度或高度大於這裏的最大值,則會對圖片進行壓縮,指定成0的話就表示無論圖片有多大,都不會進行壓縮.
        // maxHeight:容許圖片最大的高度
        // decodeConfig:圖片的顏色屬性
        // errorListener:圖片請求失敗的回調
    }

ImageRequest和StringRequest差很少,不過能夠經過設置maxWidth和maxHeight對圖片進行壓縮;
在上面這個請求中,咱們只把請求回來的圖片直接設置給了ImageView,並無作其它處理,是否有點不嚴謹,內存溢出了咋辦?請看下面!

4、ImageLoader

    protected void imageLoader() {
        iv = (ImageView) findViewById(R.id.iv);
        String url = "http://img0.bdstatic.com/img/image/shouye/hjxnzz04.jpg";
        ImageLoader loader = new ImageLoader(reqQueue, new BitmapCache());
        ImageListener listener = new ImageListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
            }

            @Override
            public void onResponse(ImageContainer response, boolean isImmediate) {
            }
        };
        // listener = ImageLoader.getImageListener(iv, R.drawable.ic_launcher,
        // R.drawable.ic_launcher);
        loader.get(url, listener, 0, 0);
        // ImageLoader明顯要比ImageRequest更加高效,它不只能夠幫咱們對圖片進行緩存,還能夠過濾掉重複的連接,避免重複發送請求.
        // 它的內部也是使用ImageRequest來實現的;
    }

ImageLoader功能就要強大一些,它能夠對圖片進行緩存,其實它內部仍是經過ImageRequest來實現的;經過ImageLoader.get(url,listener,maxWidth,maxHeight)自動獲取圖片;若是須要詳細的監聽圖片的獲取過程,則new一個ImageListener實例,若是不須要,則經過ImageLoader.getImageListener(int defaultResouceId,int errorResourceId);來設置默認的圖片和請求失敗時的圖片;
在建立ImageLoader實例的時候,須要一個ImageCache對象,我在這裏簡單自定義了一個ImageCache對象用於緩存圖片;

public class BitmapCache implements ImageCache {
    public static int getDefaultLruCacheSize() {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;
        return cacheSize;
    }

    private final String tag = "BitmapCache";
    private LruCache<String, Bitmap> mCache;

    public BitmapCache() {
        int maxSize = getDefaultLruCacheSize();
        mCache = new LruCache<String, Bitmap>(maxSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes() * bitmap.getHeight();
            }
        };
    }

    @Override
    public Bitmap getBitmap(String url) {
        Log.e(tag, "getBitmap");
        return mCache.get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        Log.e(tag, "putBitmap");
        mCache.put(url, bitmap);
    }
}

5、NetworkImageView

    protected void networkImageView() {
        String url = "http://img0.bdstatic.com/img/image/shouye/hjxnzz04.jpg";
        NetworkImageView niv = ...;
        niv.setErrorImageResId(R.drawable.ic_launcher);
        niv.setDefaultImageResId(R.drawable.ic_launcher);
        ImageLoader loader = new ImageLoader(reqQueue, new BitmapCache());
        niv.setImageUrl(url, loader);
        // NetworkImageView是一個自定義控制,它是繼承自ImageView的,在原生的基礎之上加入了加載網絡圖片的功能
        // 使用ImageRequest和ImageLoader這兩種方式來加載網絡圖片,均可以傳入一個最大寬度和高度的參數來對圖片進行壓縮,
        // 但NetworkImageView並不須要提供任何設置最大寬高的方法也可以對加載的圖片進行壓縮.
        // 這是因爲NetworkImageView是一個控件,在加載圖片的時候它會自動獲取自身的寬高,而後對比網絡圖片的寬度,再決定是否須要對圖片進行壓縮.
        // 也就是說,壓縮過程是在內部徹底自動化的,並不須要咱們關心,NetworkImageView會始終呈現給咱們一張大小剛恰好的網絡圖片.
    }

NetworkImageView繼承處ImageView,它的使用更加簡單,它的一些特性上面已經列出,使用的時候直接把原始的ImageView替換便可;

6、補充

上面講了幾個經常使用的類的使用,下面對一些設置進行補充記錄一下;
上面的網絡請求都是最基本的請求,並無帶特定的參數,那麼問題來了,若是我須要設定一些請求參數怎麼辦?請看下面!

Request在發出請求的時候,會調用兩個方法getParams和getHeaders,分別讀取請求時附帶的參數和請求頭,咱們重寫這兩方法,把須要設置的參數給寫進去便可,下面是一個簡單的例子;

        StringRequest sr = new StringRequest(Method.GET, url,
                new Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        Log.e(tag, "" + response);
                    }
                }, new ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                    }
                }) {
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> map = new HashMap<String, String>();
                map.put("param1", "value1");
                map.put("param2", "value2");
                return map;
            }

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                Map<String, String> map = new HashMap<String, String>();
                map.put("Content-Type", "application/json");
                return map;
            }
        };

7、管理緩存

<1>.RequestQueue默認會把數據緩存到本地,好比一張圖片,一些相關方法參考DiskBasedCache類;但有時咱們不須要對數據進行緩存,只須要在添加請求的時候經過Request.setShouldCache(false)便可;

<2>.查看緩存:

RequestQueue reqQueue = ...;
Cache cache = reqQueue.getCache(); Entry entry = cache.get(url); if(entry != null){ try { String data = new String(entry.data, "UTF-8"); // handle data, like converting it to xml, json, bitmap etc., } catch (UnsupportedEncodingException e) { e.printStackTrace(); } }else{ // Cached response doesn't exists. Make network call here }

Cache還提供了其它相關的方法,好比remove{刪除},invalidate{不會刪除緩存的數據,而是使其失效,當網絡請求成功獲取到新數據時,會覆蓋掉以前的數據},clear{清空};

除了使用Cache.clear()方法清空緩存,還有另一種方法來請空緩存:

    protected void clearCache() {
        ClearCacheRequest ccr = new ClearCacheRequest(reqQueue.getCache(),
                new Runnable() {
                    @Override
                    public void run() {
                    }
                });
        ccr.setTag(this);
        reqQueue.add(ccr);
    }

8、取消請求

有時候,咱們可能須要手動取消請求,好比,在一個請求還未完成時,程序即出了,若是再繼續請求沒有太大的意義,還有可能形成程序崩潰,一般這種狀況咱們在onStop方法中取消請求,下面就來看看如何取消請求;

RequestQueue reqQueue ...;        
reqQueue.cancelAll(this); // reqQueue.cancelAll(new RequestFilter() { // @Override // public boolean apply(Request<?> request) { // return false; // } // });

9、自定義Request

先來看StringRequest的源碼實現

public class StringRequest extends Request<String> {
    private final Listener<String> mListener;

    /**
     * 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;
    }

    /**
     * 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);
    }

    @Override
    protected void deliverResponse(String response) {
        mListener.onResponse(response);
    }

    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        String parsed;
        try {
            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對你們來講都沒有太大的難度,也就是重寫兩個方法,deliverResponse(僅僅一行代碼,有什麼難的?)和parseNetworkResponse,主要就是實現parseNetworkResponse,下面參照StringRequest來實現一個XmlRequest;

public class XmlRequest extends Request<XmlPullParser> {
    private Listener<XmlPullParser> listener;

    public XmlRequest(int method, String url, Listener<XmlPullParser> listener,
            ErrorListener errorlistener) {
        super(method, url, errorlistener);
        this.listener = listener;
    }

    public XmlRequest(String url, Listener<XmlPullParser> listener,
            ErrorListener errorlistener) {
        this(Method.GET, url, listener, errorlistener);
    }

    @Override
    protected Response<XmlPullParser> parseNetworkResponse(
            NetworkResponse response) {
        try {
            String str = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers));
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser parser = factory.newPullParser();
            parser.setInput(new StringReader(str));
            return Response.success(parser,
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (Exception e) {
            return Response.error(new ParseError());
        }
    }

    @Override
    protected void deliverResponse(XmlPullParser response) {
        listener.onResponse(response);
    }
}

10、自定義Request2(GsonRequest)

對於上面的JsonObjectRequest,咱們只是獲得了JSONObject,聯想Gson,咱們是否也能夠直接把獲取到的Json數據轉換爲一個實體對象呢?固然能夠,並且也很是簡單;

public class GsonRequest<T> extends Request<T> {
    private Listener<T> listener;
    private Gson gson;
    private Class<T> clazz;

    public GsonRequest(int method, String url, Class<T> clazz,
            Listener<T> listener, ErrorListener errorlistener) {
        super(method, url, errorlistener);
        this.listener = listener;
        this.clazz = clazz;
        gson = new Gson();
    }

    public GsonRequest(String url, Class<T> clazz, Listener<T> listener,
            ErrorListener errorlistener) {
        this(Method.GET, url, clazz, listener, errorlistener);
    }

    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse response) {
        try {
            String str = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers));
            return Response.success(gson.fromJson(str, clazz),
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        }
    }

    @Override
    protected void deliverResponse(T response) {
        listener.onResponse(response);
    }
}

 

 

完!

 

參考:http://www.androidhive.info/2014/05/android-working-with-volley-library-1/

相關文章
相關標籤/搜索