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. 使用CSV控件方法实现参数化

    一.录制脚本 二.下面介绍如何使用CSV控件方法实现参数化 1.  添加-->配置元件-->csv Data Set Config Filename:文件的来源 Variable Name ...

  2. C# 两个datatable中的数据快速比较返回交集或差集[z]

    最基本的写法无非是写多层foreach循环,数据量多了,循环的次数是乘积增长的. 这里推荐使用Except()差集.Intersect()交集,具体性能没有进行对比. 如果两个datatable的字段 ...

  3. 矩阵游戏(game)

    矩阵游戏(game) --九校联考24OI__D1T1 问题描述 LZK发明一个矩阵游戏,大家一起来玩玩吧,有一个N行M列的矩阵.第一行的数字是1,2,-M,第二行的数字是M+1,M+2-2*M,以此 ...

  4. 解决js数组循环删除出错

    for(var i=0,flag=true,len=arr.length;i<len;flag ? i++ : i){ if( arr[i]&&arr[i].status==0 ...

  5. mk文件配置第三方jar包,so文件

    #-------------------------配置jar包--------------------- LOCAL_STATIC_JAVA_LIBRARIES := \ libphonenumbe ...

  6. zabbix3.0监控Windows服务器

    我们下载后,解压开始有多个文件: conf目录存放是agent配置文件bin文件存放windows下32位和64位安装程序 找到conf下的配置文件 zabbix_agentd.win.conf ,修 ...

  7. Python从入门到超神之文件处理

    一.文件处理流程(python默认是utf-8编码) 打开文件函数:open(文件路径,encoding=‘utf-8’)注意:open会检索系统的编码,所以需要调整一致否则报错 例如:fi=open ...

  8. [转]etcd 启用 https

    1, 生成 TLS 秘钥对 2,拷贝密钥对到所有节点 3,配置 etcd 使用证书 4,测试 etcd 是否正常 5,配置 kube-apiserver 使用 CA 连接 etcd 6,测试 kube ...

  9. vuex的mutations传值

    mutations是要通过方法触发的,用于更改store里的数据的.this.$store.commit("mutationsName") 例子: store.js import ...

  10. go mysql insert变量到数据库

    result, err1 := db.Exec("insert ignore into dish(name,calorie,confidence) values('"+str1+& ...