首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >13.缓存、三级缓存、内存溢出、AsyncTask

13.缓存、三级缓存、内存溢出、AsyncTask

作者头像
六月的雨
发布2018-05-14 10:56:22
1.2K0
发布2018-05-14 10:56:22
举报
文章被收录于专栏:Android开发指南Android开发指南

SharePreference工具类

  1. /** * SharePreference封装 * */ public class PrefUtils { public static final String PREF_NAME = "config"; public static boolean getBoolean(Context ctx, String key, boolean defaultValue) { SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); return sp.getBoolean(key, defaultValue); } public static void setBoolean(Context ctx, String key, boolean value) { SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); sp.edit().putBoolean(key, value).commit(); } public static String getString(Context ctx, String key, String defaultValue) { SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); return sp.getString(key, defaultValue); } public static void setString(Context ctx, String key, String value) { SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); sp.edit().putString(key, value).commit(); } }

缓存工具类

  1. public class CacheUtils { /** * 缓存原理:设置缓存 key 是url, value是json(解析出来的) */ public static void setCache(String key, String value, Context ctx) { PrefUtils.setString(ctx, key, value); // 可以将缓存放在文件中, 文件名就是Md5(url), 文件内容是json } /** * 获取缓存 key 是url */ public static String getCache(String key, Context ctx) { return PrefUtils.getString(ctx, key, null); } }

用法:

1.在请求完网络,获取json数据后保存起来

  1. private void getDataFromServer() { HttpUtils utils = new HttpUtils(); utils.send(HttpMethod.GET, GlobalContants.PHOTOS_URL, new RequestCallBack<String>() { @Override public void onSuccess(ResponseInfo<String> responseInfo) { String result = (String) responseInfo.result; parseData(result); // 设置缓存 CacheUtils.setCache(GlobalContants.PHOTOS_URL, result, mActivity); } @Override public void onFailure(HttpException error, String msg) { Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT) .show(); error.printStackTrace(); } }); }

2.在初始化数据的时候判断,可以直接解析数据,也可以什么都不做,然后获取网络数据看有没有最新的

  1. public void initData() { String cache = CacheUtils .getCache(GlobalContants.PHOTOS_URL, mActivity); if (!TextUtils.isEmpty(cache)) { // parseData(cache); } getDataFromServer(); }

解析数据

  1. protected void parseData(String result) { Gson gson = new Gson(); PhotosData data = gson.fromJson(result, PhotosData.class); mPhotoList = data.data.news;// 获取组图列表集合 if (mPhotoList != null) { mAdapter = new PhotoAdapter(); lvPhoto.setAdapter(mAdapter); gvPhoto.setAdapter(mAdapter); } }

三级缓存

- 内存缓存, 优先加载, 速度最快 - 本地缓存, 次优先加载, 速度快 - 网络缓存, 不优先加载, 速度慢,浪费流量

服务器端下载的图片是使用 Http的缓存机制,每次执行将本地图片的时间发送给服务器,如果返回码是 304,说明服务端的图片和本地的图片是相同的,直接使用本地保存的图片,如果返回码是 200,则开始下载新的图片并实现缓存。在从服务器获取到图片后,需要再在本地和内存中分别存一份,这样下次直接就可以从内存中直接获取了,这样就加快了显示的速度,提高了用户的体验。

内存溢出OOM

导致内存泄漏主要的原因是,先前申请了内存空间而忘记了释放。如果程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,因为无法让垃圾回收器GC验证这些对象是否不再需要。如果存在对象的引用,这个对象就被定义为"有效的活动",同时不会被释放。要确定对象所占内存将被回收,我们就要务必确认该对象不再会被使用。典型的做法就是把对象数据成员设为null或者从集合中移除该对象。但当局部变量不需要时,不需明显的设为null,因为一个方法执行完毕时,这些引用会自动被清理

内存溢出(oom) out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。

内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。memory leak会最终会导致out of memory!

解决方法1:java中的引用(使用软引用)

    - 强引用 垃圾回收器不会回收, java默认引用都是强引用     - 软引用 SoftReference   在内存不够时,垃圾回收器会考虑回收     - 弱引用 WeakReference  在内存不够时,垃圾回收器会优先回收     - 虚引用 PhantomReference  在内存不够时,垃圾回收器最优先回收 注意: Android2.3+, 系统会优先将SoftReference的对象提前回收掉, 即使内存够用

解决方法2:LruCache 

    least recentlly use 最少最近使用算法     会将内存控制在一定的大小内, 超出最大值时会自动回收, 这个最大值开发者自己定 解决方法3:图片压缩

xutils就是这个原理,现在不用xutils,现在自定义几个工具类

1.自定义加载工具类

  1. public class MyBitmapUtils { NetCacheUtils mNetCacheUtils; LocalCacheUtils mLocalCacheUtils; MemoryCacheUtils mMemoryCacheUtils; public MyBitmapUtils() { mMemoryCacheUtils = new MemoryCacheUtils(); mLocalCacheUtils = new LocalCacheUtils(); mNetCacheUtils = new NetCacheUtils(mLocalCacheUtils, mMemoryCacheUtils); } public void display(ImageView ivPic, String url) { ivPic.setImageResource(R.drawable.news_pic_default);// 设置默认加载图片 Bitmap bitmap = null; // 从内存读 bitmap = mMemoryCacheUtils.getBitmapFromMemory(url); if (bitmap != null) { ivPic.setImageBitmap(bitmap); System.out.println("从内存读取图片啦..."); return; } // 从本地读 bitmap = mLocalCacheUtils.getBitmapFromLocal(url); if (bitmap != null) { ivPic.setImageBitmap(bitmap); System.out.println("从本地读取图片啦..."); mMemoryCacheUtils.setBitmapToMemory(url, bitmap);// 将图片保存在内存 return; } // 从网络读 mNetCacheUtils.getBitmapFromNet(ivPic, url); } }

2.网络缓存、AsyncTask

  1. public class NetCacheUtils { private LocalCacheUtils mLocalCacheUtils; private MemoryCacheUtils mMemoryCacheUtils; public NetCacheUtils(LocalCacheUtils localCacheUtils, MemoryCacheUtils memoryCacheUtils) { mLocalCacheUtils = localCacheUtils; mMemoryCacheUtils = memoryCacheUtils; } /** * 从网络下载图片 * * @param ivPic * @param url */ public void getBitmapFromNet(ImageView ivPic, String url) { new BitmapTask().execute(ivPic, url);// 启动AsyncTask, // 参数会在doInbackground中获取 } /** * Handler和线程池的封装 * * 第一个泛型: 参数类型 第二个泛型: 更新进度的泛型, 第三个泛型是onPostExecute的返回结果 * * @author Kevin * */ class BitmapTask extends AsyncTask<Object, Void, Bitmap> { private ImageView ivPic; private String url; /** * 后台耗时方法在此执行, 子线程 */ @Override protected Bitmap doInBackground(Object... params) { ivPic = (ImageView) params[0]; url = (String) params[1]; ivPic.setTag(url);// 将url和imageview绑定 return downloadBitmap(url); } /** * 更新进度, 主线程 */ @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); } /** * 耗时方法结束后,执行该方法, 主线程 */ @Override protected void onPostExecute(Bitmap result) { if (result != null) { String bindUrl = (String) ivPic.getTag(); if (url.equals(bindUrl)) {// 确保图片设定给了正确的imageview ivPic.setImageBitmap(result); mLocalCacheUtils.setBitmapToLocal(url, result);// 将图片保存在本地 mMemoryCacheUtils.setBitmapToMemory(url, result);// 将图片保存在内存 System.out.println("从网络缓存读取图片啦..."); } } } } /** * 下载图片 * * @param url * @return */ private Bitmap downloadBitmap(String url) { HttpURLConnection conn = null; try { conn = (HttpURLConnection) new URL(url).openConnection(); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); conn.setRequestMethod("GET"); conn.connect(); int responseCode = conn.getResponseCode(); if (responseCode == 200) { InputStream inputStream = conn.getInputStream(); //图片压缩处理 BitmapFactory.Options option = new BitmapFactory.Options(); option.inSampleSize = 2;//宽高都压缩为原来的二分之一, 此参数需要根据图片要展示的大小来确定 option.inPreferredConfig = Bitmap.Config.RGB_565;//设置图片格式 Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option); return bitmap; } } catch (Exception e) { e.printStackTrace(); } finally { conn.disconnect(); } return null; } }

3.本地缓存(SD卡),一般会以MD5加密文件名

  1. public class LocalCacheUtils { public static final String CACHE_PATH = Environment .getExternalStorageDirectory().getAbsolutePath() + "/zhbj_cache_52"; /** * 从本地sdcard读图片 */ public Bitmap getBitmapFromLocal(String url) { try { String fileName = MD5Encoder.encode(url); File file = new File(CACHE_PATH, fileName); if (file.exists()) { Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream( file));//decodeStream放的是输入输出流 return bitmap; } } catch (Exception e) { e.printStackTrace(); } return null; } /** * 向sdcard写图片 * * @param url * @param bitmap */ public void setBitmapToLocal(String url, Bitmap bitmap) { try { String fileName = MD5Encoder.encode(url); File file = new File(CACHE_PATH, fileName); File parentFile = file.getParentFile(); if (!parentFile.exists()) {// 如果文件夹不存在, 创建文件夹 parentFile.mkdirs(); } // 将图片保存在本地 bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(file));//100是质量 } catch (Exception e) { e.printStackTrace(); } }

3.内存缓存:

内存中使用LRUCache是最合适的。如果用HashMap来实现,不是不可以,但需要注意在合适的时候释放缓存。至于具体怎么释放,我没考虑过,但用软引用的问题在于,你很难控制缓存的大小,也就是说,只有等到你的内存快要撑爆,你的图片缓存才会被回收。是不是感觉傻傻的?

  1. public class MemoryCacheUtils { // private HashMap<String, SoftReference<Bitmap>> mMemoryCache = new // HashMap<String, SoftReference<Bitmap>>();//一开始使用map,后来使用软引用 private LruCache<String, Bitmap> mMemoryCache; public MemoryCacheUtils() { long maxMemory = Runtime.getRuntime().maxMemory() / 8;//主流都是分配16m的8/1 mMemoryCache = new LruCache<String, Bitmap>((int) maxMemory) { @Override protected int sizeOf(String key, Bitmap value) { int byteCount = value.getRowBytes() * value.getHeight();// 获取图片占用内存大小 return byteCount; } }; } /** * 从内存读 * * @param url */ public Bitmap getBitmapFromMemory(String url) { // SoftReference<Bitmap> softReference = mMemoryCache.get(url); // if (softReference != null) { // Bitmap bitmap = softReference.get(); // return bitmap; // } return mMemoryCache.get(url); } /** * 写内存 * * @param url * @param bitmap */ public void setBitmapToMemory(String url, Bitmap bitmap) { // SoftReference<Bitmap> softReference = new // SoftReference<Bitmap>(bitmap); // mMemoryCache.put(url, softReference); mMemoryCache.put(url, bitmap); } }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-10-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
图片处理
图片处理(Image Processing,IP)是由腾讯云数据万象提供的丰富的图片处理服务,广泛应用于腾讯内部各产品。支持对腾讯云对象存储 COS 或第三方源的图片进行处理,提供基础处理能力(图片裁剪、转格式、缩放、打水印等)、图片瘦身能力(Guetzli 压缩、AVIF 转码压缩)、盲水印版权保护能力,同时支持先进的图像 AI 功能(图像增强、图像标签、图像评分、图像修复、商品抠图等),满足多种业务场景下的图片处理需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档