避免出现bitmap内存限制OUT OF MEMORY的一种方法

在编写Android程序的时候,我们总是难免会碰到OOM(OUT OF MEMORY)的错误,那么这个错误究竟是怎么来的呢,可以先看一下这篇文章ANDROID
BITMAP内存限制OOM,OUT OF MEMORY

 

这里,我使用Gallery来举例,在模拟器中,不会出现OOM错误,但是,一旦把程序运行到真机里,图片文件一多,必然会出现OOM,我们通过做一些额外的处理来避免。

1.创建一个图片缓存对象HashMap<Integer,Bitmap> dataCache,integer对应Adapter中的位置position,我们只用缓存处在显示中的图片,对于之外的位置,如果dataCache中有对应的图片,我们需要进行回收内存。在这个例子中,Adapter对象的getView方法首先判断该位置是否有缓存的bitmap,如果没有,则解码图片(bitmapDecoder.getPhotoItem,BitmapDecoder类见后面)并返回bitmap对象,设置dataCache在该位置上的bitmap缓存以便之后使用;若是该位置存在缓存,则直接取出来使用,避免了再一次调用底层的解码图像需要的内存开销。有时为了提高Gallery的更新速度,我们还可以预存储一些位置上的bitmap,比如存储显示区域位置外向上3个向下3个位置的bitmap,这样上或下滚动Gallery时可以加快getView的获取。

		public View getView(int position, View convertView, ViewGroup parent) {

			if(convertView==null){
				LayoutInflater inflater  = LayoutInflater.from(context);
				convertView = inflater.inflate(R.layout.photo_item, null);

	            holder = new ViewHolder();
	            holder.photo = (ImageView) convertView.findViewById(R.id.photo_item_image);
	            holder.photoTitle = (TextView) convertView.findViewById(R.id.photo_item_title);
	            holder.photoDate = (TextView) convertView.findViewById(R.id.photo_item_date);
	            convertView.setTag(holder);
			}else {
		       holder = (ViewHolder) convertView.getTag();
		    }
			cursor.moveToPosition(position);

			Bitmap current = dateCache.get(position);
			if(current != null){//如果缓存中已解码该图片,则直接返回缓存中的图片
				holder.photo.setImageBitmap(current);
			}else {
				current = bitmapDecoder.getPhotoItem(cursor.getString(1), 2) ;
				holder.photo.setImageBitmap(current);
				dateCache.put(position, current);
			}
			holder.photoTitle.setText(cursor.getString(2));
			holder.photoDate.setText(cursor.getString(4));
			return convertView;
		}

	}

BitmapDecoder.java

package com.wuyi.bestjoy;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;

public class BitmapDecoder {
	private static final String TAG = "BitmapDecoder";
	private Context context;
	public BitmapDecoder(Context context) {
		this.context = context;
	}

	public Bitmap getPhotoItem(String filepath,int size) {
	      BitmapFactory.Options options = new BitmapFactory.Options();
  	      options.inSampleSize=size;
  	      Bitmap bitmap = BitmapFactory.decodeFile(filepath,options);
  	      bitmap=Bitmap.createScaledBitmap(bitmap, 180, 251, true);//预先缩放,避免实时缩放,可以提高更新率
	      return bitmap;

	}
}

2.由于Gallery控件的特点,总有一个item处于当前选择状态,我们利用此时进行dataCache中额外不用的bitmap的清理,来释放内存。

@Override
	public void onItemSelected(AdapterView<?> parent, View view, int position,long id) {

		releaseBitmap();
		Log.v(TAG, "select id:"+ id);
	}

private void releaseBitmap(){
    //在这,我们分别预存储了第一个和最后一个可见位置之外的3个位置的bitmap
    //即dataCache中始终只缓存了(M=6+Gallery当前可见view的个数)M个bitmap
		int start = mGallery.getFirstVisiblePosition()-3;
		int end = mGallery.getLastVisiblePosition()+3;
		Log.v(TAG, "start:"+ start);
		Log.v(TAG, "end:"+ end);
		//释放position<start之外的bitmap资源
		Bitmap delBitmap;
		for(int del=0;del<start;del++){
			delBitmap = dateCache.get(del);
			if(delBitmap != null){
                                //如果非空则表示有缓存的bitmap,需要清理
				Log.v(TAG, "release position:"+ del);
				//从缓存中移除该del->bitmap的映射
                                dateCache.remove(del);
				delBitmap.recycle();
			}
		}

		freeBitmapFromIndex(end);

	}

	/**
	 * 从某一位置开始释放bitmap资源
	 * @param index
	 */
	private void freeBitmapFromIndex(int end) {
		//释放之外的bitmap资源
		Bitmap delBitmap;
		for(int del =end+1;del<dateCache.size();del++){
			delBitmap = dateCache.get(del);
			if(delBitmap != null){
				dateCache.remove(del);
				delBitmap.recycle();
				Log.v(TAG, "release position:"+ del);
			}

		}
	}

 经过这些额外的操作,有效的避免了OOM的问题。

时间: 2024-10-28 14:50:02

避免出现bitmap内存限制OUT OF MEMORY的一种方法的相关文章

管理bitmap内存

在上个章节<如何缓存你的Bitmap>中,说明了Bitmap对象的缓存与回收.本章来说Bitmap对象内存的管理,由于Adroid版本的差异,所以bitmap的内存管理方式有所不同. 先来简单说下Android系统各个版本管理Bitmap内存的差异,看看管理Bitmap的进化史. Android2.2及以下:当垃圾回收器回收时线程停止,导致渲染延迟.Android2.3以后增加了concurrent垃圾回收器,意味着不再引用的Bitmap对象能够立即回收. Android2.3.3及以下:Bi

ThinkPHP提示错误Fatal error: Allowed memory size的解决方法_php实例

本文实例讲述了ThinkPHP提示错误Fatal error: Allowed memory size的解决方法.分享给大家供大家参考.具体分析如下: 如果你的ThinkPHP提示你:致命错误(Fatal error: Allowed memory size),根据网上说的提高服务器可使用内存,我觉得都不是好的解决办法.麻烦也没必要.因为这是ThinkPHP本身存在BUG. 错误提示:Fatal error: Allowed memory size of 1073741824 bytes exh

Git使用小坑 Out of memory错误的解决方法_服务器其它

最近公司将内部使用的代码由svn迁到了git上,所以也必须学者使用Git命令. 虽说git的模式和svn区别很大,但想必也不是什么难事.但没曾想在第一步git clone的时候就踩到了一个大坑--废话不多提,先看错误代码: 复制代码 代码如下: Cloning into XXXX... remote: Couting objects: 125627, done. remote: Compressing objects: 100% (47061/47061), done. fatal: Out o

C++内存分配五种方法的区别

在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区. 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区.里面的变量通常是局部变量.函数参数等. 堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete.如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收. 自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的.

重装win8系统内存占用忽高忽低的解决方法

  很多win8用户在使用一段时间后,系统就会变得特别的卡顿,故此很多用户都会选择对win8系统重装,但同样问题有来了,用户在重装win8系统后,出现内存不稳定,忽高忽低的问题,对于出现该问题是什么原因造成的?我们应用如何解决呢?下面看河东软件园小编为您带来的详细操作方法! 情况1: Win8系统,任何一款操作系统在运行时,电脑内存使用率都会出现时高时低的情况.应用程序等开的多了,占用的内存空间多了,内存自然就高.相反,程序使用的少了,内存自然就低了.同时,应用程序在运行过程中对内存的占用率也是

Win7系统重启后蓝屏提示beginning dump of physical memory错误代码的解决方法

  Win7系统中打开某个程序的时候,突然间就重启了,然后出现蓝屏,还提示"beginning dump of physical memory",具体现象如下所示: Win7蓝屏原因及解决方法: 1.内存条接触不良或兼容性不太好 解决方法:拔下内存条用橡皮擦擦金手指再装回去试试,还不行,交换一下内存插槽位置插回去试试; 2.板卡接触不良或品质问题致设备运行不稳定 解决方法:关机把所有硬件重新插一下,避免有虚接的情况; 3.硬件兼容性较差 解决方法:这种情况常见于非品牌的组装兼容机上,没

Windows中提高内存使用效率5种方法

  如何优化内存的管理,提高内存的使用效率,尽可能地提高运行速度,是大家所关心的问题.下面介绍在Windows操作系统中,提高内存的使用效率和优化内存管理的5种方法. 方法一:调整高速缓存区域的大小 可以在"计算机的主要用途"选项卡中设置系统利用高速缓存的比例(针对Windows 98).如果系统的内存较多,可选择"网络服务器",这样系统将用较多的内存作为高速缓存.在CD-ROM标签中,可以直接调节系统用多少内存作为CD-ROM光盘读写的高速缓存. 方法二:(违禁词

c++-C++中这样写会不会内存泄漏,有没有好的实现方法

问题描述 C++中这样写会不会内存泄漏,有没有好的实现方法 template class Foo { public: Foo(T T_val); Foo& operator=(const Foo& f); virtual ~Foo(); const T& getTval(); private: const T T_val; }; template Foo::Foo(T T_val = NULL):T_val(T_val) { ; } template Foo::~Foo() {}

Android编程实现获取系统内存、CPU使用率及状态栏高度的方法示例

本文实例讲述了Android编程实现获取系统内存.CPU使用率及状态栏高度的方法.分享给大家供大家参考,具体如下: DeviceInfoManage类用于获取系统的内存,CPU的信息,以及状态栏的高度 import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReade