• 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类库,添加相关权限

      <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中的核心类

      • Request,请求类,有几个实现类
        • StringRequest:请求的时候直接回来一个String
        • JsonObjectRequest:请求的时候直接回来一个JsonObject
        • JsonArrayRequest:请求的时候直接回来一个JsonArray
        • ImageRequest:请求的时候直接回来一个Bitmap
        • 自定义请求:一会我们会结合gson
      • RequestQueue:请求队列,用来执行Request的
      • ImageLoader:图片加载的类
      • NetWorkImageView:继承自ImageView,可以直接加载网络图片
    • 创建请求队列RequestQueue

      RequestQueue queue = Volley.newRequestQueue(this);
    • 使用StringRequest进行请求

      //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进行请求

      //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的倍数,代码如下:

      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,能降低一半内存:

      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);
        }
    }
  • 相关阅读:
    高质量的函数 —— 《clean code》读后感
    保证代码的高质量 —— 《clean code》读后感
    [转 TDD] 如何坚持TDD:使用者出现的问题以及解决方案
    注释 —— 《clean code》读后感
    注释 —— 《clean code》读后感
    如何命名 —— 《clean code》读后感
    高质量的函数 —— 《clean code》读后感
    保证代码的高质量 —— 《clean code》读后感
    格式 —— 《clean code》读后感
    华为内部面试题库(14)
  • 原文地址:https://www.cnblogs.com/yegong0214/p/6498450.html
Copyright © 2020-2023  润新知