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

      


 
 
 
 
 
 
 

附件列表

13.缓存、三级缓存、内存溢出、AsyncTask的更多相关文章

  1. 【转】android加载大量图片内存溢出的三种解决办法

    方法一: 在从网络或本地加载图片的时候,只加载缩略图. /** * 按照路径加载图片 * @param path 图片资源的存放路径 * @param scalSize 缩小的倍数 * @return ...

  2. android加载大量图片内存溢出的三种方法

    android加载大量图片内存溢出的三种解决办法 方法一:  在从网络或本地加载图片的时候,只加载缩略图. /** * 按照路径加载图片 * @param path 图片资源的存放路径 * @para ...

  3. Android 图片三级缓存之内存缓存(告别软引用(SoftRefrerence)和弱引用(WeakReference))

    因为之前项目同事使用了图片三级缓存,今天整理项目的时候发现同事还是使用了软引用(SoftRefrerence)和弱引用(WeakReference),来管理在内存中的缓存.看到这个我就感觉不对了.脑海 ...

  4. android文件缓存,并SD卡创建目录未能解决和bitmap内存溢出解决

    1.相关代码: 加入权限: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" ...

  5. 关于Android中的三级缓存

    三级缓存的提出就是为了提升用户体验.当我们第一次打开应用获取图片时,先到网络去下载图片,然后依次存入内存缓存,磁盘缓存,当我们再一次需要用到刚才下载的这张图片时,就不需要再重复的到网络上去下载,直接可 ...

  6. Android 的图片异步请求加三级缓存 ACE

    使用xUtils等框架是很方便,但今天要用代码实现bitmapUtils 的功能,很简单, 1 AsyncTask请求一张图片 ####AsyncTask #####AsyncTask是线程池+han ...

  7. android 项目学习随笔十八(三级缓存)

    xUtils的BitmapUtils模块用的就是三级缓存,在项目中尽量还是应用BitmapUtils 三级缓存(机制) import com.itheima.zhsh66.R; import andr ...

  8. Android中图片的三级缓存

    为什么要使用三级缓存 如今的 Android App 经常会需要网络交互,通过网络获取图片是再正常不过的事了 假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量.在当前的状况下,对于非wifi ...

  9. Android进阶图片处理之三级缓存方案

    图片的三级缓存 一.概述 一開始在学习Android的时候.处理图片的时候,每次获取图片都是直接从网络上面载入图片. 可是在开发项目的过程中,每次点击进入app里面,图片都要慢慢的再一次从网络上面载入 ...

随机推荐

  1. Zookeeper配置文件

    zookeeper的默认配置文件为zookeeper/conf/zoo_sample.cfg,需要将其修改为zoo.cfg.其中各配置项的含义,解释如下: 1.tickTime:Client-Serv ...

  2. ROS零门槛学渣教程系列(二十)——ROSJAVA和Android

    ros wiki地址:http://wiki.ros.org/android 第一步:安装JDK (参考博文:https://blog.csdn.net/Hong_A/article/details/ ...

  3. optional的使用

    :first-child { margin-top: 0px; } .markdown-preview:not([data-use-github-style]) h1, .markdown-previ ...

  4. Electorn(桌面应用)自动化测试之Java+selenium实战例子

    基于electorn的桌面应用,网上相关资料较少.所有记录一下.使用java+selenium+testng对该类型应用的自动化测试方法. 代码样例 package com.contract.web. ...

  5. SpringBoot跨域问题

    1.先来说说跨域原理: 跨域原理简单来说就是发起跨域请求的时候,浏览器会对请求域返回的响应信息检查HTTP头,如果Access-Control-Allow-Origin包含了自身域,则允许访问,否则报 ...

  6. SringMVC概述

    Spring为展现层提供的基于MVC设计理念的优秀的WEB框架,是目前最主流的MVC框架之一. Spring3.0后全面超越Struts2.0,成为最优秀的MVC框架,SpringMVC通过一套注解, ...

  7. Java 学习路线图

    一.集合 集合类的分类 * (一)List 结构集合类 * ArrayList LinkedList Vector Stack * (二)Map 结构集合类 * HashMap HashTable * ...

  8. 环境搭建文档——Windows下的Python3环境搭建

    前言 背景介绍: 自己用Python开发了一些安卓性能自动化测试的脚本, 但是想要运行这些脚本的话, 本地需要Python的环境. 测试组的同事基本都没有安装Python环境, 于是乎, 我就想直接在 ...

  9. asp.net 抽象方法和虚方法的用法区别,用Global类重写Application_BeginRequest等方法为例子

    不废话,直接贴代码 public abstract class LogNetGlobal : System.Web.HttpApplication { protected void Applicati ...

  10. Sql Server常用数据库函数小结

    查询验证存储过程是否存在 SELECT name FROM sysobjects WHERE  xtype = 'P' and name = '{0}' ----------------------- ...