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. go语言学习逻辑运算符if判断,iota的理解

    第一天学习go语言,首先吐槽一下,配置go语言浪费了我两个小时的时间 不是在百度,就是在百度的路上,这里介绍一下我的go语言的版本和开发平台 go语言1.12版本,之前没有用过在早的版本了首先记录一下 ...

  2. centos-1 nginx

    常用命令 su #切换用户mkdir flodr #创建目录rm -r flodr #删除文件/目录,有提示rm -rf flodr #删除文件/目录,无提示pwd #查看当前路径  防火墙设置 ht ...

  3. double team

    队长博客链接 https://www.cnblogs.com/98-10-22-25/p/9806296.html 团队队名 泡面 团队成员 211606361 何承华(队长) 211606356 陈 ...

  4. Mac使用笔记大全

    1.mac中,怎么直接在当前文件夹打开终端? 步骤:(1)在键盘-快捷键-服务,勾选“新建位于文件夹位置的终端窗口”.(2)然后在需要打开终端的文件夹上,右键,“新建位于文件夹位置的终端窗口”即可. ...

  5. android shape 怎么在底部画横线

    使用layer-list可以,画了两层 1 2 3 4 5 6 7 8 9         <layer-list>             <!-- This is the lin ...

  6. 单点登录的三种实现方式 转自: https://blog.csdn.net/python_tty/article/details/53113612

    单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任.单点登录在大型网站里使用得 ...

  7. 《Linux就该这么学》第十六天课程

    今天笔记有点少就不发了,分享一下第23章 使用OpenLDAP部署目录服务很实用 下面是DHCP动态管理地址,如需深入学习请前往 https://www.linuxprobe.com/chapter- ...

  8. IDEA中通过工具类实现对数据库的增删改查

    package com.hu.dao; import com.hu.entity.Student; import java.util.List;import java.util.Map; public ...

  9. centos6安装oracle时运行./runInstaller无法弹出图形界面

    首先确保安装oracle的机器上安装了图形化界面. 1.利用xmanager登录到安装oracle的服务器上(直接用root用户登录) 2.运行 export DISPLAY=你的本机地址:0.0 3 ...

  10. Ubuntu搭建Anki服务器

    Ubuntu搭建Anki服务器 第一步安装Anki 阿里云的服务器,xshell远程登录上 #以root用户进行操作 #安装Akni服务 easy_install AnkiServer #添加名为an ...