Android Volley的请求封装,实现图片内存缓存(防止OOM),数据磁盘缓存,及清除磁盘缓存
来源:互联网 发布:控制网络与现场总线 编辑:程序博客网 时间:2024/04/30 23:10
平时经常用到Volley请求网络数据,因为它确实好用,简单方便,因为项目要求也不是很苛刻,所以。。。。
呃。。。程序员总会去重构自己的代码,这不,我自己研究源码和网上的一些方法,重构了自己方便用的代码,在这顺便记录一下。
关于缓存,百度了好多,网上都是些什么研究源码的。。。呃,我想说,你们就别复制粘贴了,够多了!却很少有说这么用的。
不多废话,正题。。。
一:第一部分,实现内存缓存
1.因为图片是很占内存的,一不小心就Boom。。。Boom。。。Boom了,下面是写一个图片内存缓存的类MImgCache.java ,看代码:
import android.graphics.Bitmap;import android.util.LruCache;import com.android.volley.toolbox.ImageLoader;/** * Created by qinlang on 2015/10/21. */public class MImgCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache { private static int MAX_SIZE = 10 * 1024 * 1024;//内存缓存大小,10M /** * @param maxSize for caches that do not override {@link #sizeOf}, this is * the maximum number of entries in the cache. For all other caches, * this is the maximum sum of the sizes of the entries in this cache. */ public MImgCache(int maxSize) { super(maxSize); } public MImgCache() { this(MAX_SIZE); } @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } @Override public Bitmap getBitmap(String url) { return get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { put(url, bitmap); }}代码很简单,就是使用LruCache,然后再指定内存大小什么的。
2.接着自己写了一个工厂类VolleyFactroy.java,单例模式,目的是为了一个应用程序只能有一个请求队列:
import android.content.Context;import com.android.volley.Request;import com.android.volley.RequestQueue;import com.android.volley.toolbox.Volley;/** * Created by qinlang on 2015/10/21. */public class VolleyFactroy { private RequestQueue requestQueue; private Context context; private MImgCache imgCache; private static final int MAX_DISK_CACHE = 20 * 1024 * 1024;//磁盘缓存20M private VolleyFactroy(Context context) { this.context = context; requestQueue = getRequestQueue(); imgCache = new MImgCache(); } private static VolleyFactroy instance; /** * 新的实例 * * @param context * @return */ public static synchronized VolleyFactroy getInstance(Context context) { if (instance == null) instance = new VolleyFactroy(context); return instance; } /** * 获取请求队列 * * @return */ public RequestQueue getRequestQueue() { if (requestQueue == null) requestQueue = Volley.newRequestQueue(context.getApplicationContext(), MAX_DISK_CACHE);//实例一个请求队列,并初始化磁盘缓存大小 return requestQueue; } /** * 添加下载队列 * * @param request * @param <T> */ public <T> void addRequest(Request<T> request) { getRequestQueue().add(request); } /** * 取消下载队列 * * @param tag */ public void cancelRequest(Object tag) { getRequestQueue().cancelAll(tag); } /** * 获取内存缓存对象 * * @return */ public MImgCache getImgCache() { return imgCache; }}
呃。。。这样已经能使用内存缓存了,只要你用这个工厂类拿到的请求队列,图片加载什么的。。。还会那么容易OOM?。
其实我也不知道这样写好不好,反正写着写着就变这样了,反正还蛮好用的,我也不保证完全正确。
二:磁盘缓存部分(有三个决定因素)
当然这里不只是磁盘缓存,因为你会发现上面的代码用起来很不方便,不是吗?下面我们再对上面进一步封装,
让自己用起来so easy。。。
这次我不写工厂类了,我写一个工具类。是的,没错,你们不也最喜欢工具类了?
代码就懒得分了,全在下面,不难,该有注释的地方都有了,慢慢看。
import android.app.Application;import android.content.Context;import android.graphics.Bitmap;import android.os.Handler;import android.os.Message;import android.text.TextUtils;import android.widget.ImageView;import com.android.volley.AuthFailureError;import com.android.volley.Cache;import com.android.volley.DefaultRetryPolicy;import com.android.volley.NetworkError;import com.android.volley.NoConnectionError;import com.android.volley.ParseError;import com.android.volley.Request;import com.android.volley.RequestQueue;import com.android.volley.Response;import com.android.volley.ServerError;import com.android.volley.TimeoutError;import com.android.volley.VolleyError;import com.android.volley.toolbox.DiskBasedCache;import com.android.volley.toolbox.ImageLoader;import com.android.volley.toolbox.StringRequest;import com.zzgx.warner.utils.Lg;import java.io.File;import java.util.HashMap;import java.util.Map;/** * Volley工具类 * * @author Created by qinlang on 2016/3/3. last update at 2017.03 */public class VolleyUtils { private static Context context; private static RequestQueue requestQueue; /** * 返回数据成功 */ public static final int RESULT_SUCCESS = 200; /** * 返回数据失败 */ public static final int RESULT_FAIL = 201; private static int timeOut = 10000;//超时时间 public static final String TAG = "volley_requestQueue"; private static final String DEFAULT_CACHE_DIR = "volley";//Volley默认缓存路径,不可更改 private static VolleyFactroy volleyFactroy; private static VolleyUtils volleyUtils; private final File cacheDir; private static DiskBasedCache diskBasedCache; private static HashMap这下是不是好用很多了,即可以发送GET请求,有可以发送POST请求,还实现了磁盘缓存。tagMap; public static VolleyUtils getInstance() { if (null == context) { throw new RuntimeException("Must be use init(context) in Application"); } if (null == volleyUtils) { volleyUtils = new VolleyUtils(context); } return volleyUtils; } public static void init(Context context) { if (context == null) { throw new IllegalArgumentException("context can not be null"); } if (!(context instanceof Application)) { throw new RuntimeException("context must be an Application Context"); } VolleyUtils.context = context; volleyUtils = new VolleyUtils(context); } private VolleyUtils(Context context) { this.context = context; if (null == volleyFactroy) volleyFactroy = VolleyFactroy.getInstance(context); if (null == requestQueue) requestQueue = volleyFactroy.getRequestQueue(); cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);//实例化缓存路径 if (null == diskBasedCache) diskBasedCache = new DiskBasedCache(cacheDir);//实例化磁盘缓存类,用于清除缓存用 if (null == tagMap) tagMap = new HashMap<>(); tagMap.put(TAG, TAG); } /** * 发送Get请求 * * @param url 请求url * @param handler 用于发回数据的handler, * 参数:what = {成功{@link #RESULT_SUCCESS}|失败{@link #RESULT_FAIL}},agr1 = {method},obj = {result} * @param method 用于判断哪个方法在调用 */ public void sendGetRequest(final String url, String tag, final Handler handler, final int method) { sendGetRequest(url, tag, new OnRequestResultListener() { @Override public void onResponse(String response) { String jsonString = response.toString(); Message message = handler.obtainMessage(); message.what = RESULT_SUCCESS; message.arg1 = method; message.obj = jsonString; handler.sendMessage(message); } @Override public void onErrorResponse(VolleyError error, String errString) { error(error, handler, method); } }); } /** * 发送GET请求 * * @param url 请求url * @param listener 结果监听器 */ public void sendGetRequest(String url, String tag, final OnRequestResultListener listener) { if (TextUtils.isEmpty(tag)) tag = TAG; else cancleRequest(tag); tagMap.put(tag, tag); StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener () { @Override public void onResponse(String response) { String jsonString = response.toString(); listener.onResponse(jsonString); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { listener.onErrorResponse(error, error(error, null, 0)); } }); request.setShouldCache(true); request.setCacheEntry(new Cache.Entry()); request.setTag(tag);//设置标签 request.setRetryPolicy(new DefaultRetryPolicy(timeOut, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));//修改超时时间和重载次数 requestQueue.add(request); } /** * 发送Post请求 * * @param url 请求url * @param params 请求的参数集 * @param handler 用于发回数据的handler, * 参数:what = {成功{@link #RESULT_SUCCESS}|失败{@link #RESULT_FAIL}},agr1 = {method},obj = {result} * @param method 用于判断哪个方法在调用 */ public void sendPostRequest(final String url, String tag, final HashMap params, final Handler handler, final int method) { sendPostRequest(url, tag, params, new OnRequestResultListener() { @Override public void onResponse(String response) { String jsonString = response.toString(); Message message = handler.obtainMessage(); message.what = RESULT_SUCCESS; message.arg1 = method; message.obj = jsonString; handler.sendMessage(message); } @Override public void onErrorResponse(VolleyError error, String errString) { error(error, handler, method); } }); } /** * 发送POST请求 * * @param url 请求url * @param params 参数集 * @param listener 结果监听器 */ public void sendPostRequest(String url, String tag, final HashMap params, final OnRequestResultListener listener) { if (TextUtils.isEmpty(tag)) tag = TAG; else cancleRequest(tag); tagMap.put(tag, tag); StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener () { @Override public void onResponse(String response) {//成功的请求结果 String jsonString = response.toString(); listener.onResponse(jsonString); } }, new Response.ErrorListener() {//失败的请求结果 @Override public void onErrorResponse(VolleyError error) { listener.onErrorResponse(error, error(error, null, 0)); } }) { @Override protected Map getParams() throws AuthFailureError { return params;//参数从这里进去 } /** * 设置头部信息 * @return * @throws AuthFailureError */ @Override public Map getHeaders() throws AuthFailureError { Map params = new HashMap (); params.put("Content-Type", "application/x-www-form-urlencoded");//发送的参数以表单形式 return params; } }; request.setShouldCache(true);//是否启用缓存,默认已经启用,可不用设置 request.setCacheEntry(new Cache.Entry());//设置缓存实体对象,注意:这里是重点,如果为null则不会有缓存 request.setTag(tag);//设置标签 request.setRetryPolicy(new DefaultRetryPolicy(timeOut, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));//修改超时时间和重载次数 requestQueue.add(request); } /** * 处理错误 * * @param error * @param handler * @param method */ private String error(VolleyError error, Handler handler, int method) { String err = "请求失败!"; if (error instanceof NetworkError) { err = "网络异常!"; } else if (error instanceof ServerError) { err = "系统繁忙!"; } else if (error instanceof AuthFailureError) { err = "请求验证失败!"; } else if (error instanceof ParseError) { err = "请求解析错误!"; } else if (error instanceof NoConnectionError) { err = "无法连接!"; } else if (error instanceof TimeoutError) { err = "请求超时!"; } if (null != handler) { Message message = handler.obtainMessage(); message.what = RESULT_FAIL; message.arg1 = method; message.obj = err; handler.sendMessage(message); } return err; } /** * 加载图片 * * @param url 图片url * @param result 回调,bitmap加载失败时为null */ public void loadImg(String url, final IBitmapResult result) { getImageLoader().get(url, new ImageLoader.ImageListener() { @Override public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) { Bitmap bitmap = response.getBitmap(); result.onResult(bitmap); } @Override public void onErrorResponse(VolleyError error) { result.onResult(null); } }); } /** * 加载图片 * * @param url 图片url * @param imageView * @param defaultImageResId 默认时显示的图片资源 * @param errorImageResId 加载错误时显示的图片资源 */ public void loadImg(String url, ImageView imageView, int defaultImageResId, int errorImageResId) { getImageLoader().get(url, ImageLoader.getImageListener(imageView, defaultImageResId, errorImageResId)); } /** * 移除指定缓存 * * @param method 方法名 请参阅{@link Request.Method},GET为0,POST为1;如此条数据用GET方式请求得到的,则参数为{@link Request.Method #GET} * @param url 请求url */ public void removeCache(Request.Method method, String url) { diskBasedCache.remove(method + ":" + url);//参数为key,默认:请求方法名+“:”+url } /** * 清除所有缓存 */ public void clearAllCache() { diskBasedCache.clear(); } /** * 设置超时时间,默认10s * * @param timeOut */ public void setTimeOut(int timeOut) { this.timeOut = timeOut; } /** * 取消全部请求 */ public void cancleAllRequest() { if (null != requestQueue && null != tagMap) { for (Map.Entry entry : tagMap.entrySet()) { requestQueue.cancelAll(entry.getValue()); } } } /** * 取消请求 * * @param tag tag */ public void cancleRequest(String tag) { if (null != tagMap) { if (!TextUtils.isEmpty(tag) && tagMap.containsKey(tag)) { requestQueue.cancelAll(tag); } } } /** * 获取请求队列 * * @return */ public RequestQueue getRequestQueue() { return requestQueue; } /** * 获取工厂类 * * @return */ public VolleyFactroy getVolleyFactroy() { return volleyFactroy; } /** * 获取ImageLoader * * @return */ public ImageLoader getImageLoader() { return new ImageLoader(requestQueue, volleyFactroy.getImgCache()); } /** * 请求结果监听器 */ public interface OnRequestResultListener { /** * 成功的请求 * * @param response 请求返回的字符串 */ void onResponse(String response); /** * 失败的请求 * * @param error * @param errString */ void onErrorResponse(VolleyError error, String errString); } /** * 加载图片的回调 */ public interface IBitmapResult { /** * 加载结果 * * @param bitmap */ void onResult(Bitmap bitmap); }}
看代码,要实现磁盘缓存,你会发现里面有两个要点
1.一个是是否可缓存,true为可缓存,false为不可缓存,其实volley内部已经默认缓存,所以这个不用理会都没事。啪。。。那你还说
setShouldCache(true);2.设置缓存实体,如果为null,即传null给它或者不重写那个方法,则不会有缓存功能。这个是第二限制条件
setCacheEntry(new Cache.Entry());
3.服务器端必须设置头部,告诉Volley这条数据是可以缓存的
response.setHeader("cache-control", "public, max-age=43200");
“缓存控制,公有(可以为私有),最大生命。。。”
没错,三个条件成立,volley才会自动帮您保存缓存,缓存也才会有效果。
上面代码可能有点乱啊,其实清除缓存可以单独用的:
private static final String DEFAULT_CACHE_DIR = "volley";//Volley默认缓存路径 private DiskBasedCache diskBasedCache;if (null == diskBasedCache) diskBasedCache = new DiskBasedCache(cacheDir);//实例化磁盘缓存类,用于清除缓存用/** * 移除指定缓存 * * @param method 方法名 请参阅{@link com.android.volley.Request.Method},GET为0,POST为1,其它方法请加对应的即可 * @param url 请求url */ public void removeCache(int method, String url) { if (method == Request.Method.GET) diskBasedCache.remove("0:" + url);//参数为key,默认为请求方法名+“:”+url else if (method == Request.Method.POST) diskBasedCache.remove("1:" + url); } /** * 清除所有缓存 */ public void clearAllCache() { diskBasedCache.clear(); }
到这就基本结束了。。。。本人用着感觉还很方便的,我们用volley无非就是发送一些简单的请求,
用ImageLoader加载图片什么的(ImageLoader里面已经写好了,可直接拿去用)。
下面附加怎么用:
发送GET/POST请求
<pre name="code" class="html">HashMap<String, String> params = new HashMap<>();params.put("...", "...");//...
<pre name="code" class="html"><pre name="code" class="html"><pre name="code" class="html"> private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); int what = msg.what; int method = msg.arg1; String result = (String) msg.obj; if (method == METHOD) { if (what == VolleyUtils.RESULT_SUCCESS) { }else if(what == VolleyUtils.RESULT_FAIL){} } } };
VolleyUtils.getInstance(this).sendPostRequest(URL, params, handler, METHOD);
GET请求还更简单,就不贴了。
ImageLoader的使用
ImageLoader imageLoader = VolleyUtils.getInstance(this).getImageLoader();imageLoader.get(imgUrl, ImageLoader.getImageListener(imageView, R.drawable.ic_default_avatar, R.drawable.ic_default_avatar));
注意:清除缓存,因为可以单独使用,你那条数据用的什么方法请求就用什么方法的参数,
如:用GET请求则volleyUtils.removeCache(0, url); GET的值为0。清除全部则顺便。
最后,顺便说一下,写这些遇到的坑,因为网上都是那些七七八八的什么源码分析,一看就恼火,那时候没找到,然后还是看了好多,收货好多
,还是不行。不找了,然后看了一晚上的源码,自己找。再加网上的一些解释,最后还是弄好了,当时那个服务器加头部的网上找半天也没见有说。
清除缓存也是,网上一点资料没擦边,还是看了一个多小时源码理清它的流程,找到方法的(其实也没那么难,但是网上就是没有),亲测清除成功。
0 0
- Android Volley的请求封装,实现图片内存缓存(防止OOM),数据磁盘缓存,及清除磁盘缓存
- Android Volley图片缓存机制结合DiskLruCache实现磁盘缓存
- Android Volley框架的使用(四)图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- Android Volley框架的使用(四)图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- Android Volley框架的使用(四)图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- Android Volley框架的使用(四)图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- Android Volley框架的使用(四)图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- Android Volley框架的使用(四)图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- Android Volley框架的使用之图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- Android内存缓存和磁盘缓存的实现
- 内存缓存+磁盘缓存
- 图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- 图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- 图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- 图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- Part1:Volley磁盘缓存
- 图片磁盘缓存量的大小显示和,清除缓存实现 ------ 基于glide
- 强制Volley缓存图片到磁盘
- 面向对象设计原则
- 基于tensorflow的MNIST手写数字识别(二)--入门篇
- Atitit.获得向上向下左的右的邻居的方法 软键盘的设计..
- Java读写txt或doc文件
- 理解C语言中指针的声明以及复杂声明的语法
- Android Volley的请求封装,实现图片内存缓存(防止OOM),数据磁盘缓存,及清除磁盘缓存
- 你给的,真的是用户想要的么?
- JAVA类库/JAVA API
- 二阶魔方
- 循环队列 输出杨辉三角
- 新浪云服务上线项目
- deepin使用向日葵远程控制(修改run.sh)
- [Android Studio / NDK] 如何使用javah生成.h文件
- Https加密及攻防