Android 如何走出OutOfMemoryError:位图大小超出VM预算
我是android新手,尝试使用位图和BitmapFactory将SD卡图像放到网格视图中。 但它会导致如下错误:Android 如何走出OutOfMemoryError:位图大小超出VM预算,android,layout,widget,Android,Layout,Widget,我是android新手,尝试使用位图和BitmapFactory将SD卡图像放到网格视图中。 但它会导致如下错误: ERROR/AndroidRuntime(6137): java.lang.OutOfMemoryError: bitmap size exceeds VM budget ERROR/AndroidRuntime(6137): at android.graphics.BitmapFactory.nativeDecodeStream(Native Metho
ERROR/AndroidRuntime(6137): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
ERROR/AndroidRuntime(6137): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
ERROR/AndroidRuntime(6137): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459)
ERROR/AndroidRuntime(6137): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:271)
不要先将完整质量的图像复制到应用程序中。使用
选项
类对质量/大小进行抽样:
ContentResolver cr = getContentResolver();
InputStream is = cr.openInputStream(chosenImageUri);
Options optionSample = new BitmapFactory.Options();
optionSample.inSampleSize = 4; // Or 8 for smaller image
Bitmap bitmap = BitmapFactory.decodeStream(is, null, optionSample);
// Bitmap bitmap = BitmapFactory.decodeFile(filePathString, optionSample);
如果要创建缩略图位图,请尝试使用inSampleSize=8
如果您发现自己创建了多个位图对象,每个对象都对同一图像进行了一些更改,请尝试使用Bitmap.recycle()
。但是recycle()
如果您的应用程序引用了一些旧位图(可能很难检测),则可能会导致一些运行时错误,因此请小心使用它
如果有帮助,请告诉我。不要先将完整质量的图像复制到应用程序中。使用
选项
类对质量/大小进行抽样:
ContentResolver cr = getContentResolver();
InputStream is = cr.openInputStream(chosenImageUri);
Options optionSample = new BitmapFactory.Options();
optionSample.inSampleSize = 4; // Or 8 for smaller image
Bitmap bitmap = BitmapFactory.decodeStream(is, null, optionSample);
// Bitmap bitmap = BitmapFactory.decodeFile(filePathString, optionSample);
如果要创建缩略图位图,请尝试使用inSampleSize=8
如果您发现自己创建了多个位图对象,每个对象都对同一图像进行了一些更改,请尝试使用Bitmap.recycle()
。但是recycle()
如果您的应用程序引用了一些旧位图(可能很难检测),则可能会导致一些运行时错误,因此请小心使用它
如果有帮助,请告诉我。Android更关心内存,BitmapFactory只接受有限大小的图像 我认为以下内容将帮助您在使用前缩放图像
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
public class ImageScale
{
/**
* Decodes the path of the image to Bitmap Image.
* @param imagePath : path of the image.
* @return Bitmap image.
*/
public Bitmap decodeImage(String imagePath)
{
Bitmap bitmap=null;
try
{
File file=new File(imagePath);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(file),null,o);
final int REQUIRED_SIZE=200;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true)
{
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize=scale;
bitmap=BitmapFactory.decodeStream(new FileInputStream(file), null, options);
}
catch(Exception e)
{
bitmap = null;
}
return bitmap;
}
/**
* Resizes the given Bitmap to Given size.
* @param bm : Bitmap to resize.
* @param newHeight : Height to resize.
* @param newWidth : Width to resize.
* @return Resized Bitmap.
*/
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth)
{
Bitmap resizedBitmap = null;
try
{
if(bm!=null)
{
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
}
}
catch(Exception e)
{
resizedBitmap = null;
}
return resizedBitmap;
}
}
Android更关心内存,BitmapFactory只接受有限大小的图像 我认为以下内容将帮助您在使用前缩放图像
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
public class ImageScale
{
/**
* Decodes the path of the image to Bitmap Image.
* @param imagePath : path of the image.
* @return Bitmap image.
*/
public Bitmap decodeImage(String imagePath)
{
Bitmap bitmap=null;
try
{
File file=new File(imagePath);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(file),null,o);
final int REQUIRED_SIZE=200;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true)
{
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize=scale;
bitmap=BitmapFactory.decodeStream(new FileInputStream(file), null, options);
}
catch(Exception e)
{
bitmap = null;
}
return bitmap;
}
/**
* Resizes the given Bitmap to Given size.
* @param bm : Bitmap to resize.
* @param newHeight : Height to resize.
* @param newWidth : Width to resize.
* @return Resized Bitmap.
*/
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth)
{
Bitmap resizedBitmap = null;
try
{
if(bm!=null)
{
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
}
}
catch(Exception e)
{
resizedBitmap = null;
}
return resizedBitmap;
}
}
好吧,显然这个问题将在第100次得到回答。我的想法是:
- 首先,根据设备上的Android版本: 如果您使用的是Android 2.x及以下版本(蜂窝之前的任何版本),位图实例占用的内存将不会反映在Runtime.getRuntime().xxxMemory()方法报告的堆上的可用内存量中。这些实例放在堆外的内存中。如果要跟踪位图实例将使用多少内存,必须手动计算为imageWidth*imageHeight*4。这将为您提供映像在(堆外)内存中获取的字节。此内存消耗以及堆上内存消耗的总和必须低于Android为特定设备上的应用程序分配的最大内存,否则将出现OutOfMemory错误
- Android分配给进程的总内存在很大程度上取决于设备和Android版本。这可能在16到48兆之间。在旧设备上是16或32。较新的是32或48。这一点,您必须单独检查每个您想要瞄准的设备。您也可以在运行时执行此操作,并将其用作您可以在内存中放入多少内容的指南(可能您希望在将图像加载到为应用程序分配16 Mb内存的设备上之前先对其进行减采样)
- 在Android蜂巢(3.x.x版)及更高版本上,位图实例将在堆内存上使用。这使得跟踪加载图像后仍有多少可用内存变得更容易。同样在这些版本的Android中,位图实例将被自动垃圾收集(如果可能)。在蜂巢前,你必须打电话 Bitmap.recycle()
- 使用BitmapFactory解码图像(并创建位图实例)时,可以传入选项,例如仅获取图像的宽度和高度,或在解码前对其进行下采样。这可以帮助您在实际将图像放入内存之前评估图像将占用多少内存。查看文档:
- 如果你觉得有冒险精神,你可以一起欺骗内存限制,尽管这并不适用于所有设备:创建OpenglSurfaceView,并将图像显示为四边形上的纹理。为了简单起见,可以使用正交投影(如果只需要给出2d的外观)。这里的诀窍是,您可以将图像作为位图加载到内存中,将其指定给OpenGL纹理并清除该位图实例。实际图像仍将从纹理对象显示,并且这些对象不受每进程内存限制的限制
- 首先,根据设备上的Android版本: 如果您使用的是Android 2.x及以下版本(蜂窝之前的任何版本),位图实例占用的内存将不会反映在Runtime.getRuntime().xxxMemory()方法报告的堆上的可用内存量中。这些实例放在堆外的内存中。如果要跟踪位图实例将使用多少内存,必须手动计算为imageWidth*imageHeight*4。这将为您提供映像在(堆外)内存中获取的字节。此内存消耗以及堆上内存消耗的总和必须低于Android为特定设备上的应用程序分配的最大内存,否则将出现OutOfMemory错误
- Android分配给进程的总内存在很大程度上取决于设备和Android版本。这可能在16到48兆之间。在旧设备上是16或32。较新的是32或48。这一点,您必须单独检查每个您想要瞄准的设备。您也可以在运行时执行此操作,并将其用作您可以在内存中放入多少内容的指南(可能您希望在将图像加载到为应用程序分配16 Mb内存的设备上之前先对其进行减采样)
- 在Android蜂巢(3.x.x版)及更高版本上,位图实例将在堆内存上使用。这使得追踪m是如何
- 好吧,显然这个问题将在第100次得到回答。我的想法是: