Altough我在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);
有什么问题?如果您需要有关代码的其他信息,我可以添加它。 谢谢!
答案 0 :(得分:127)
您无法动态增加堆大小,但可以通过使用来请求使用更多。
机器人: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;
}
注意:计算两个幂的幂,因为解码器使用a 最终值通过向下舍入到最接近的2的幂,按照
inSampleSize
文档。
要使用此方法,首先将inJustDecodeBounds
设置为true
进行解码,传递选项,然后使用新的inSampleSize
值再次解码,inJustDecodeBounds
设置为{ {1}}:
false
此方法可以轻松地将任意大尺寸的位图加载到显示100x100像素缩略图的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);
}
中,如以下示例代码所示:
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;
}
这不是一个好主意,谷歌的摘录解释了它,
但是,请求大堆的功能仅适用于a 一小组应用程序,可以证明需要消耗更多的RAM(例如 作为一个大型照片编辑应用程序)。永远不要简单地请求大堆 因为你已经没有内存而你需要快速修复 - 你应该这样做 只有当你确切知道所有记忆的存在时才使用它 分配以及必须保留的原因。然而,即使你有信心 你的应用程序可以证明大堆的合理性,你应该避免请求它 尽可能的。使用额外的内存将越来越多 因为垃圾而损害整体用户体验 收集将花费更长时间,系统性能可能会更慢 任务切换或执行其他常见操作。
在与android:largeHeap="true"
一起工作之后,我会说将这个添加到清单中以避免问题不是罪恶
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来验证正在使用的运行时(&#34; java.vm.version&#34;)。如果正在使用ART,则该属性的值为&#34; 2.0.0&#34;或更高。
此外,Android开源项目(AOSP)正在开发一个压缩垃圾收集器,以改善内存管理。因此,您应该避免使用与压缩GC不兼容的技术(例如保存指向对象实例数据的指针)。这对于使用Java Native Interface(JNI)的应用程序尤为重要。有关更多信息,请参阅防止JNI问题。
此外,您可以使用本机内存(NDK&amp; JNI),因此实际上可以绕过堆大小限制。
以下是一些关于它的帖子:
这是一个为它制作的图书馆:
答案 1 :(得分:3)
我只看到两个选项:
答案 2 :(得分:3)
处理位图时应该实现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?
OR
使用像Universal Image Loader这样的层库:
https://github.com/nostra13/Android-Universal-Image-Loader
编辑:
现在处理图像时大部分时间都是使用位图我使用Glide来配置Glide模块和LRUCache
答案 3 :(得分:1)
为Android应用程序处理此类错误/异常的提示很少:
活动&amp;应用程序具有以下方法:
标签可以具有属性&#39; largeHeap&#39;设置为TRUE,为App沙箱请求更多堆。
管理内存缓存&amp;磁盘缓存:
使用WeakReference,Java实例创建的SoftReference,特别是文件。
如果图像太多,请使用适当的库/数据结构来管理内存,使用加载的图像,处理磁盘缓存。
处理OutOfMemory异常
遵循编码的最佳做法
最小化活动堆栈,例如堆栈中的活动数量(不要在上下文/活动中保存所有内容)
尽量减少使用静力学,更多的单身人士。
照顾OS基本内存基础
当您确定不再需要内存中缓存时,有时会手动调用GC.Collect()。
答案 4 :(得分:1)
如果收到此错误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" />
答案 5 :(得分:0)
android:largeHeap="true"
无法解决错误
在我的情况下,通过将SVG转换为矢量将图标/图像添加到Drawable文件夹后,出现了此错误。简单地,转到图标xml文件并为宽度和高度设置小数字
android:width="24dp"
android:height="24dp"
android:viewportWidth="3033"
android:viewportHeight="3033"
答案 6 :(得分:0)
我直接通过 XML (app:srcCompat
) 在 imageview 中加载了一个 ~350kB 的图像,这导致了 OOM 错误并且应用程序崩溃了。
为了解决这个问题,我使用 Glide 将完全相同的图像加载到同一个图像视图中,并且成功了!
<块引用>