虽然我在drawable文件夹中的图像非常小,但我从用户那里得到了这个错误。我没有在代码中使用任何位图功能。至少故意:)
java.lang.OutOfMemoryError
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:683)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:513)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:889)
at android.content.res.Resources.loadDrawable(Resources.java:3436)
at android.content.res.Resources.getDrawable(Resources.java:1909)
at android.view.View.setBackgroundResource(View.java:16251)
at com.autkusoytas.bilbakalim.SoruEkrani.cevapSecimi(SoruEkrani.java:666)
at com.autkusoytas.bilbakalim.SoruEkrani$9$1.run(SoruEkrani.java:862)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5602)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
根据这个stackTrace,我在这一行得到了这个错误('tv'是一个textView):
tv.setBackgroundResource(R.drawable.yanlis);
问题是什么?如果您需要有关代码的其他信息,我可以添加它。谢谢!
您无法动态增加堆大小,但可以通过使用请求使用更多。
机器人:largeHeap = “真”
在manifest.xml
中,您可以在清单中添加这些线条,它适用于某些情况。
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
是否应使用大型Dalvik堆创建应用程序的进程。这适用于为应用程序创建的所有进程。它仅适用于加载到进程中的第一个应用程序;如果您使用共享用户ID以允许多个应用程序使用进程,则它们都必须一致地使用此选项,否则它们将具有不可预测的结果。大多数应用程序不应该需要这个,而应该专注于减少其整体内存使用量以提高性能。启用此功能也不能保证可用内存的固定增加,因为某些设备受其总可用内存的限制。
要在运行时查询可用的内存大小,请使用方法getMemoryClass()
或getLargeMemoryClass()
。
如果仍然面临问题,那么这也应该有效
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
mBitmapInsurance = BitmapFactory.decodeFile(mCurrentPhotoPath,options);
这是BitmapFactory.Options.inSampleSize在显示图像速度方面的最佳用法。文档提到使用2的幂的值,所以我正在使用2,4,8,16等。
例如,如果将最终显示在ImageView
中的128x128像素缩略图中,则不值得将1024x768像素图像加载到内存中。
要告诉解码器对图像进行二次采样,将较小的版本加载到内存中,请在inSampleSize
对象中将true
设置为BitmapFactory.Options
。例如,使用inSampleSize
为4解码的分辨率为2100 x 1500像素的图像产生大约512x384的位图。将其加载到内存中对于完整图像使用0.75MB而不是12MB(假设ARGB_8888
的位图配置)。这是一种根据目标宽度和高度计算样本大小值的方法,该值为2的幂:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
注意:计算两个幂的幂是因为解码器使用最终值,通过舍入到最接近的2的幂,根据
inSampleSize
文档。
要使用此方法,首先使用设置为inJustDecodeBounds
的true
进行解码,传递选项,然后使用新的inSampleSize
值和inJustDecodeBounds
设置为false
再次解码:
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
此方法可以轻松地将任意大尺寸的位图加载到显示100x100像素缩略图的ImageView
中,如以下示例代码所示:
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
您可以按照类似的过程解码来自其他来源的位图,方法是根据需要替换相应的BitmapFactory.decode*
方法。
我发现这段代码也很有趣:
private Bitmap getBitmap(String path) {
Uri uri = getImageUri(path);
InputStream in = null;
try {
final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
in = mContentResolver.openInputStream(uri);
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, o);
in.close();
int scale = 1;
while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) >
IMAGE_MAX_SIZE) {
scale++;
}
Log.d(TAG, "scale = " + scale + ", orig-width: " + o.outWidth + ",
orig-height: " + o.outHeight);
Bitmap bitmap = null;
in = mContentResolver.openInputStream(uri);
if (scale > 1) {
scale--;
// scale to max possible inSampleSize that still yields an image
// larger than target
o = new BitmapFactory.Options();
o.inSampleSize = scale;
bitmap = BitmapFactory.decodeStream(in, null, o);
// resize to desired dimensions
int height = bitmap.getHeight();
int width = bitmap.getWidth();
Log.d(TAG, "1th scale operation dimenions - width: " + width + ",
height: " + height);
double y = Math.sqrt(IMAGE_MAX_SIZE
/ (((double) width) / height));
double x = (y / height) * width;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, (int) x,
(int) y, true);
bitmap.recycle();
bitmap = scaledBitmap;
System.gc();
} else {
bitmap = BitmapFactory.decodeStream(in);
}
in.close();
Log.d(TAG, "bitmap size - width: " +bitmap.getWidth() + ", height: " +
bitmap.getHeight());
return bitmap;
} catch (IOException e) {
Log.e(TAG, e.getMessage(),e);
return null;
}
使用android:largeHeap="true"
这不是一个好主意,谷歌的摘录解释了它,
但是,请求大堆的能力仅适用于一小部分可以证明需要消耗更多RAM的应用程序(例如大型照片编辑应用程序)。永远不要因为内存不足而需要快速修复而请求大堆 - 只有当您确切知道所有内存的分配位置以及必须保留的原因时才应使用它。然而,即使你确信你的应用程序可以证明大堆的合理性,你应该避免在任何可能的范围内请求它。使用额外的内存将越来越不利于整体用户体验,因为当任务切换或执行其他常见操作时,垃圾收集将花费更长时间并且系统性能可能更慢。
在与out of memory errors
激动地工作之后,我会说将此添加到清单中以避免问题不是罪
Android运行时(ART)是运行Android 5.0(API级别21)及更高版本的设备的默认运行时。此运行时提供了许多功能,可以提高Android平台和应用程序的性能和平滑度。您可以在Introducing ART找到有关ART新功能的更多信息。
但是,一些适用于Dalvik的技术不适用于ART。通过本文档,您可以了解迁移现有应用以与ART兼容时需要注意的事项。大多数应用程序应该在使用ART时运行。
在Dalvik下,应用程序经常发现显式调用System.gc()来提示垃圾收集(GC)很有用。对于ART来说,这应该是不太必要的,特别是如果您正在调用垃圾收集以防止GC_FOR_ALLOC类型的出现或减少碎片。您可以通过调用System.getProperty(“java.vm.version”)来验证正在使用的运行时。如果正在使用ART,则该属性的值为“2.0.0”或更高。
此外,Android开源项目(AOSP)正在开发一个压缩垃圾收集器,以改善内存管理。因此,您应该避免使用与压缩GC不兼容的技术(例如保存指向对象实例数据的指针)。这对于使用Java Native Interface(JNI)的应用程序尤为重要。有关更多信息,请参阅防止JNI问题。
ART的JNI比Dalvik更严格。使用CheckJNI模式来捕捉常见问题是一个特别好的主意。如果您的应用程序使用C / C ++代码,则应查看以下文章:
此外,您可以使用本机内存(NDK和JNI),因此您实际上绕过了堆大小限制。
以下是一些关于它的帖子:
这是一个为它制作的图书馆:
我只看到两个选项:
在处理位图时应该实现LRU缓存管理器
http://developer.android.com/reference/android/util/LruCache.html http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html When should I recycle a bitmap using LRUCache?
要么
使用像Universal Image Loader这样的层库:
https://github.com/nostra13/Android-Universal-Image-Loader
编辑:
现在处理图像时大部分时间都使用位图我使用Glide来配置Glide模块和LRUCache
为Android应用程序处理此类错误/异常的提示很少:
如果你得到这个错误java.lang.OutOfMemoryError这是Android中最常见的问题。当由于内存空间不足而无法分配对象时,Java虚拟机(JVM)会抛出此错误。
在这样的应用程序下试试这个android:hardwareAccelerated="false" , android:largeHeap="true"
你的manifest.xml文件:
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:hardwareAccelerated="false"
android:largeHeap="true" />