应用程序OOM异常永远都是值得关注的问题。通常这一块也是程序这中的重点之一

首先,OOM就是内存溢出,即Out Of Memory。也就是说内存占有量超过了VM所分配的最大。

怎么解决OOM,通常OOM都发生在需要用到大量内存的情况下(创建或解析Bitmap,分配特大的数组等),在这样的一种情况下,就可能出现OOM,据我现在了解到,多数OOM都是因为Bitmap太大。所以,这里我就专门针对如何解决Bitmap的OOM。其实最核发的就是只加载可见范围内的Bitmap,试想这样一种情况,在GridView或ListView中,数据量有5000,每一屏只显示20个元素,那么不可见的,我们是不需要保存Bitmap在内在中的。所以我们就是只把那么可见的Bitmap保留在内存中,那些不可见的,就释放掉。当元素滑出来时,再去加载Bitmap。

这里我有两种方式,都可以避免OOM。

一,主动释放Bitmap的内存

这种方式我简单说一下,不太推荐,这也是我最开始使用的一种方法,但最后证明它不是最好的。(不推荐)

它的本质思路是:

1、只加载可见区域的Bitmap

2、滑动时不加载

3、停止滑动(Idle)后,开始重新加载可见区域的图片

4、释放滑出可见区域的Bitmap的内在。

它比较复杂:

1、我们需要监听GridView/ListView的滑动事件,这个很简单做到,AbsListView#setOnScrollListener(OnScrollListener l)

2、主动调用Bitmap#recycle()方法,它会导致一个问题,必须判断这个Bitmap是否被一个View(ImageView等)所引用,如果被引用,我们不能简单地调用recycle()方法,这样会导致异常,说是View使用了一个已经被回收的Bitmap。

3,我们必须设计自己的线程来控制开始/暂停等,因为GridView/ListView的滑动状态可能不断地变化,也就是说滑动->停止->滑动,这种状态可能不断变化,这样就会导致我们的线程中的run()方法里面的逻辑比较复杂,一旦复杂,问题就可能就得更多。

基于以上几点,这种方式不是最好的,所以不推荐。

二,设计Cache

这种方式,我觉得是比较好的一种,它首先利用了cache,我认为cache是一个很重要的东西,把Bitmap的内存单独放在一个地方来管理,这个地方就是cache,它的容量是一定的,我们可能会不断的向这个cache中添加元素,也可能不断的移除元素。

为了更好的说明这种方式,先要介绍一下LruCache。

LruCache

1、这其实就是一个LinkedHashMap,任意时刻,当一个值被访问时,它就会被移动到队列的开始位置,所以这也是为什么要用LinkedHashMap的原因,因为要频繁的做移动操作,为了提高性能,所以要用LinkedHashMap。当cache满了时,此时再向cache里面添加一个值,那么,在队列最后的值就会从队列里面移除,这个值就有可能被GC回收掉。

2、如果我们想主动释放内存,也是可以的,我们可以重写entryRemoved(Boolean, K, V, V)方法。

3、这个类是线程安全的,在多线程下面使用这个类,没不会存在问题。

synchronized (cache) {

if (cache.get(key) == null) {

cache.put(key, value);

}}

4、LruCache的APILevel是12,也就是说,我们在SDK 2.3.x以下是无法使用的,但是没关系,LruCache的源码不算复杂,我们可以直接把它拷贝到自己的工程目录就可以了。

AsyncTask<>

这个类也是一个很重要也很常用的类。它封装了Thread和Handler,我们使用就更加方便,不用关注Handler,我们知道,在后台线程中是不能更新UI,而很多情况下,我们在后台线程做完一件事情后,一般都会更新UI,一般的做法是向关联到UI线程的Handler发送一个message,在Handler里面去处理这个message,从而更新UI。用了AsyncTask之后,我们就不用关注Handler了。这个类有几个重要的方法:

1、onPreExecute(): 在UI线程里面调用,它在这个task执行后会立即调用。我们在这个方法里面通常是用于建立一个任务,比如显示一个等待对话框来通知用户。

2、doInBackground(Params...):这个方法从名字就可以看出,它是运行在后台线程的,在这个方法里面,去做耗时的事情,比如下载访问网络,操作文件等。这这个方法里面,我们可以调用publishProgress(Progress...)来调用当前任务的进度,调用了这个方法后,对应的onProgressUpdate(Progress...)方法会被调用,这个方法是运行在UI线程的。

3、onProgressUpdate(Progress...):运行在UI线程,在调用publishProgress()方法之后。这个方法用来在UI上显示任何形式的进度,比如你可以显示一个等待对话框,也可以显示一个文本形式的log,还可以显示toast对话框。

4、onPostExecute(Result):当task结束后调用,它运行在UI线程。

5、取消一个task,我们可以在任何时候调用cancel(Boolean)来取消一个任务,当调用了cancel()方法后,onCancelled(Object)方法就会被调用,onPostExecute(Object)方法不会被调用,在doInBackground(Object[])方法中,我们可以用isCancelled()方法来检查任务是否取消。

6、几点规则

  • AsyncTask实例必须在UI线程中创建
  • execute(Params...)方法必须在UI线程中调用。
  • 不用手动调用onPreExecute(), onPostExecute(), doInBackground(), onProgressUpdate()方法。
  • 一个任务只能被执行一次。

总的思路

1、始终从cache中去取Bitmap,如果取到Bitmap,就直接把这个Bitmap设置到ImageView上面。

2、如果缓存中不存在,那么启动一个task去加载(可能从文件来,也可能从网络)。

3、每一个ImageView上面都可能绑定一个task,所以,这个ImageView必须提供一个方法能得到与之相关联的task,为什么要这样做?因为在给一个ImageView绑定task之前,必须要把原先的task取消。

4、思路很简单,但细节很多,用文字来一一说明也不太现实。我上传一个demo,大家可以参考代码和文章来理解。

OOM解决方案的更多相关文章

  1. android 帧动画的实现及图片过多时OOM解决方案(一)

    一,animation_list.xml中静态配置帧动画的顺序,如下: <?xml version="1.0" encoding="utf-8"?> ...

  2. Android OOM 解决方案

    Out of Memory(内存溢出) 几乎是每个Android程序员都会遇到的事.在网上也能找到一大堆的解决方案,之前写过一篇<Android 内存溢出管理与测试>的博文.但感觉写得不是 ...

  3. Android 开发OOM解决方案

    OOM(Out Of Memory)在加载图片过多或者过大的情况下会发生OOM,可以查看APP最高可用内存: int maxMemory = (int) (Runtim.getRuntime().ma ...

  4. NPOI导出大量数据的避免OOM解决方案【SXSSFWorkbook】

    一.NPOI的基本知识 碰到了导出大量数据的需求场景:从数据读取数据大约50W,然后再前端导出给用户,整个过程希望能较快的完成.如果不能较快完成,可以给与友好的提示. 大量数据的导出耗时的主要地方: ...

  5. Android OOM解决方案 :

    清单文件里 给Application标签加上android:largeHeap="true"这行代码   这样会给你的app分配一个大内存   如果某个页面在绘制时会耗非常多的内存 ...

  6. android 加载图片oom若干方案小结

    本文根据网上提供的一些技术方案加上自己实际开发中遇到的情况小结. 众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视手机而定).一般我们可以通过获取当 ...

  7. 一个神奇的bug:OOM?优雅终止线程?系统内存占用较高?

    摘要:该项目是DAYU平台的数据开发(DLF),数据开发中一个重要的功能就是ETL(数据清洗).ETL由源端到目的端,中间的业务逻辑一般由用户自己编写的SQL模板实现,velocity是其中涉及的一种 ...

  8. ListView异步加载网络图片完美版之双缓存技术

    本示例参考学习了一个国外的示例:http://code.google.com/p/android-imagedownloader/,有兴趣的同学下载研究一下. 问题描述:在这一篇博客中将会为大家讲解如 ...

  9. Android优化指南

    Android系统中GC内存泄漏的原因 主动回收内存System.gc();.getruntime.runtime.gc 导致内存泄漏主要的原因是,申请了内存空间而忘记了释放.如果程序中存在对无用对象 ...

随机推荐

  1. C# 排序算法记录

    class Program { static void Main(string[] args) { , , , , , , , , -, , , }; //假设一个最小的值 ]; ; i < a ...

  2. 使用log4net连接Mysql数据库配置

    log4net配置: //Author:GaoBingBing [assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net ...

  3. 看了让人笑了很多很多次的NB的痔疮经历

    前言 这篇杂记其实是去年也就是 2013年9月30日转载的,后来在整理博客分类时七弄八弄误删掉了好多文章,就包括这一篇.今天,2014年9月29日,恰好恰好一年的时候居然在好久未登陆的 OneNote ...

  4. linux远程连接客户端总结

    序:刚从阿里ECS买了一个ubuntu14.04_64_20G,但是没有提供页面登陆工具,因此从网上找了几个远程连接工具,特写在这里算是总结. 1 secureCRT SecureCRT是一款支持SS ...

  5. thinkphp中field方法

    hinkPHP的CURD操作中有很多非常实用的方法,从这篇开始,我们会为大家一一介绍. 首先为大家介绍下field方法的用法.field属于模型的连贯操作方法之一,主要目的是标识要返回或者操作的字段, ...

  6. Currency Exchange(Bellman-ford)

    Currency Exchange Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21349   Accepted: 765 ...

  7. java笔记--关于克隆技术

    关于克隆 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3884817.html"谢谢-- 1.假克隆 如: ObjectA ...

  8. HDFS深入浅析

    导读 Hadoop分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统.它和现有的分布式文件系统有很多共同点.但同时,它和其他的分布式文件系统 ...

  9. A PHP extension for Facebook's RocksDB

    A PHP extension for Facebook's RocksDB 31 commits 2 branches 0 releases 2 contributors C++ 90.5% C 8 ...

  10. jdk新特性

    自动拆装箱子: import org.junit.Test; public class Demo { /* * 自动拆装箱 * */ @Test public void ZhuangXiang() { ...