Volley的初步瞭解

Volley的介紹

  • Volley是什麼?
    • 2013年Google I/O大會上推出的網絡請求和圖片加載框架
    • 其優勢是api簡單,性能優秀
    • 很是適合數據量不大可是通訊頻繁的網絡請求,而對於大數據量的操做,如文本下載,表現則沒有那麼好
    • Volley內部仍然是使用的HttpURLConnection和HttpClient進行網絡請求的,只是對於不一樣的Android版本進行了響應的切換,2.3以前使用的HttpClient,2.3以後使用的是HttpURLConnection 這是由於在2.3版本以前,HttpURLConnection有一個很嚴重的bug,當開啓請求的時候會形成線程池沒法關閉。
  • 爲何用Volley,相比XUtil,Volley解決了如下問題:
    • 當用戶finish當前的Activity的時候,而當前Activity正在進行網絡請求,Volley支持取消網絡請求
    • 當用戶旋轉屏幕,Activity從新建立,那麼一樣的網絡請求會重新發送,而Volley支持對重複的請求進行緩存
    • 支持多樣的網絡請求返回封裝

3. Volley的使用

  • 首先,引入Volley類庫,添加相關權限java

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
  • Volley中的核心類android

    • Request,請求類,有幾個實現類
      • StringRequest:請求的時候直接回來一個String
      • JsonObjectRequest:請求的時候直接回來一個JsonObject
      • JsonArrayRequest:請求的時候直接回來一個JsonArray
      • ImageRequest:請求的時候直接回來一個Bitmap
      • 自定義請求:一會咱們會結合gson
    • RequestQueue:請求隊列,用來執行Request的
    • ImageLoader:圖片加載的類
    • NetWorkImageView:繼承自ImageView,能夠直接加載網絡圖片
  • 建立請求隊列RequestQueue算法

    RequestQueue queue = Volley.newRequestQueue(this);
  • 使用StringRequest進行請求json

    //2.建立網絡請求
    StringRequest stringRequest = new StringRequest(url, new Listener<String>() {
        @Override
        public void onResponse(String response) {
            tv_result.setText(response);
        }
    },new MyErrorListener());
    //3.執行請求
    queue.add(stringRequest);
  • 使用JsonRequest進行請求api

    //1.建立JsonRequest請求
    JsonObjectRequest joRequest = new JsonObjectRequest(url, null, new Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            tv_result.setText(response.toString());
        }
    }, new MyErrorListener());
    //2.執行請求
    queue.add(joRequest);
  • 使用JsonArrayRequest進行請求緩存

    JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(listUrl, new Listener<JSONArray>() {
        @Override
        public void onResponse(JSONArray response) {
            tv_result.setText(response.toString());
        }
    }, new MyErrorListener());
    queue.add(jsonArrayRequest);
  • 使用ImageRequest進行請求網絡

    ImageRequest imageRequest = new ImageRequest(imageUrl,new Listener<Bitmap>() {
        @Override
        public void onResponse(Bitmap response) {
            iv_result.setImageBitmap(response);
        }
    }, 200, 100, Config.RGB_565, new MyErrorListener());
    queue.add(imageRequest);

4. 加載圖片的壓縮處理的核心

  • 第一步: 從原圖進行等寬高比的採樣,採樣的值最好是2的倍數,代碼以下:app

    Options opts = new Options();
    opts.inSampleSize = 4;
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.fast, opts);
  • 第二步: 根據圖片的原始寬高比和控件的寬高比,科學的計算採樣比例,代碼以下:框架

    Options opts = new Options();
    opts.inJustDecodeBounds = true;//設置只解析圖片的邊界參數,即寬高
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.fast, opts);
    //科學計算圖片所需的採樣比例
    opts.inSampleSize = caculateSampleSize(opts.outWidth,opts.outHeight);
    
    opts.inJustDecodeBounds = false;//關閉標記,解析真實的圖片
    bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.fast, opts);
    
    /**
     * 根據圖片的原始寬高比和ImageView的寬高計算圖片的採樣比例
     * @param outWidth
     * @param outHeight
     * @return
     */
    private int caculateSampleSize(int outWidth, int outHeight) {
        int inSampleSize = 1;
        if(outWidth>outHeight){
            //參考寬進行縮放
            inSampleSize = outWidth/iv_result.getWidth();//1920/300
        }else{
            //參考高進行縮放
            inSampleSize = outHeight/iv_result.getHeight();
        }
        if(inSampleSize<1){
            inSampleSize = 1;
        }
        return inSampleSize;
    }
  • 第三步: 設置圖片加載的渲染模式爲Config.RGB_565,能下降一半內存:ide

    opts.inPreferredConfig = Config.RGB_565

5. Volley中的ImageLoader使用以及內存緩存詳解

  • 使用ImageLoader加載圖片

    protected void loadImage() {
        ImageListener imageListener = ImageLoader.getImageListener(iv_result, R.drawable.ic_launcher, R.drawable.ic_launcher);
        MemoryCache imageCache  = new MemoryCache();
        ImageLoader imageLoader = new ImageLoader(queue, imageCache);
        imageLoader.get(imageUrl, imageListener);
    }
    /**
     * 圖片內存緩存
     * @author lxj
     *
     */
    public class MemoryCache implements ImageCache{
        private LruCache<String, Bitmap> lruCache;
        //app可用內存的8分之一
        private int maxSize = (int) (Runtime.getRuntime().totalMemory()/8);
        public MemoryCache(){
            lruCache = new LruCache<String, Bitmap>(maxSize){
                @Override
                protected int sizeOf(String key, Bitmap value) {
                    return value.getHeight()*value.getRowBytes();
                }
            };
        }
        @Override
        public Bitmap getBitmap(String url) {
            return lruCache.get(url);
        }
    
        @Override
        public void putBitmap(String url, Bitmap bitmap) {
            lruCache.put(url, bitmap);
        }
    }
  • 內存緩存詳解

    • 內存緩存的存儲結構:通常是map,由於須要存取
    • 在Android2.3以前尚未好的內存緩存策略出現,通常採用SoftRefrence對Bitmap進行包裝,能儘可能保證不會出現oom,幾種引用的解釋以下:

      • 強引用 : 引用默認就是強引用, 即便內存oom, 也不會去回收對象
      • 軟應用:使用SoftRefrence去包裝一個對象,內存不足的時候去回收對象,儘可能保證不oom,代碼以下:

        HashMap<String, SoftReference<Bitmap>> map = new HashMap<String, SoftReference<Bitmap>>();
        SoftReference<Bitmap> reference = map.get(url);
        Bitmap bitmap = reference.get();
      • 弱引用:使用WeakReference保證一個對象,通常不用
    • 在Android2.3以後Google提供了Lru算法的實現類,即LruCache,並推薦咱們使用LruCache來實現圖片的內存緩存,該類有效解決了Android中圖片內存緩存的難題,常見幾種內存緩存策略有:
      • Least Frequently Used(LFU): 刪除使用頻率最少的
      • Least Recently Used(LRU): 刪除最近最少使用的
      • First in First out(FIFO): 刪除最早添加進來的
      • Most Recently Used(MRU): 刪除最近最多使用的
    • LruCache內部實現原理(重點)
      • 內部使用按照訪問順序排序的LinkedHashMap來存儲數據
      • 每次緩存命中,該條會按照元素的訪問次數進行從新排序
      • 並會判斷緩存size是否超出maxSize,若是超出則移除最下方的數據,即最少使用的數據
      • 咱們必須實現sizeOf方法,用來指定每條數據的size,此處是返回bitmap的大小
    • 瞭解XUtil等開源類庫對圖片內存緩存的實現
    • 瞭解圖片的磁盤緩存的實現DiskLruCache

6. Volley中的NetworlImageView的使用

MemoryCache imageCache  = new MemoryCache();
ImageLoader imageLoader = new ImageLoader(queue, imageCache);
net_imageview.setImageUrl(imageUrl, imageLoader);

7. 自定義Volley的Request

  • 咱們在開發中更多的是請求一個url,而後將結果解析爲java bean,因此封裝一個具備該功能的Request類,GosnRequest
  • 代碼以下:

    protected void execGsonRequest() {
        GsonRequest<Stu> gsonRequest = new GsonRequest<Stu>(url, Stu.class, new Listener<Stu>() {
            @Override
            public void onResponse(Stu stu) {
                tv_result.setText(stu.toString());
            }
        }, new MyErrorListener());
        queue.add(gsonRequest);
    }
    public class GsonRequest<T> extends Request<T>{
        private Class<T> clazz;
        private final Listener<T> mListener;
         public GsonRequest(String url,Class<T> clazz,Listener<T> listener, ErrorListener errorListener) {
            super(url, errorListener);
            mListener = listener;
            this.clazz = clazz;
        }
        @Override
        protected Response<T> parseNetworkResponse(NetworkResponse response) {
             String parsed;
                try {
                    parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                } catch (UnsupportedEncodingException e) {
                    parsed = new String(response.data);
                }
                //解析json,返回response
                T t = new Gson().fromJson(parsed,clazz );
                return Response.success(t, HttpHeaderParser.parseCacheHeaders(response));
        }
        @Override
        protected void deliverResponse(T response) {
             mListener.onResponse(response);
        }
    }

8. 使用Volley取消網絡請求

  • 給每一個Request添加tag標識

    stringRequest.setTag(this);
  • 調用取消請求的方法

    queue.cancelAll(this);

9. 使用Volley發送post請求,須要本身重寫Request的getParams方法

 public class PostReuqest extends StringRequest {
        private Map<String, String> params;
        public PostReuqest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
            super(url, listener, errorListener);
        }
        public PostReuqest(int method,String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
            super(method,url, listener, errorListener);
        }
        public void setParams(Map<String, String> params){
            this.params = params;
        }
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            return params;
        }
    }

    PostReuqest stringRequest = new PostReuqest(Request.Method.POST,Api.LOGIN, new com.android.volley.Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            text.setText(response);
        }
    }, new com.android.volley.Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    });
    HashMap<String,String> map = new HashMap<>();
    map.put("username","hehehe");
    map.put("password","12321");
    stringRequest.setParams(map);

10. 對Volley進行二次封裝

/**
 * Volley的二次封裝類
 * @author lxj
 *
 */
public class VolleyHelper {
    private RequestQueue requestQueue;
    MemoryCache imageCache  = new MemoryCache();
    private static VolleyHelper mInstance = null;
    private VolleyHelper(Context context){
        requestQueue = Volley.newRequestQueue(context);

    }
    public static VolleyHelper get(Context context){
        if(mInstance==null){
            mInstance = new VolleyHelper(context);
        }
        return mInstance;
    }
    public <T> void executeRequest(Request<T> request){
        requestQueue.add(request);
    }
    /**
     * 執行GsonRequest
     * @param url
     * @param clazz
     * @param listener
     * @param errorListener
     */
    public <T> void executeGsonRequest(String url,Class<T> clazz,Listener<T> listener,ErrorListener errorListener){
        GsonRequest<T> gsonRequest = new GsonRequest<T>(url, clazz, listener, errorListener);
        gsonRequest.setTag(url);
        requestQueue.add(gsonRequest);
    }
    /**
     * 取消請求
     * @param tag
     */
    public void cancelRequest(String tag){
        requestQueue.cancelAll(tag);
    }
    /**
     * 加載圖片
     * @param imageUrl
     * @param imageView
     */
    public void loadImage(String imageUrl,ImageView imageView){
        ImageListener imageListener = ImageLoader.getImageListener(imageView, R.drawable.ic_launcher, R.drawable.ic_launcher);
        ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
        imageLoader.get(imageUrl, imageListener);
    }
}
相關文章
相關標籤/搜索