使用 scaledBitmap 创建透明/镜像效果时避免致命内存错误
Avoiding Fatal Memory Errors while creating a transparancy / mirror image effect using scaledBitmap
我正在尝试执行一些内存管理,看来我需要先缩放图像才能使用它 - 问题是 - 我不确定如何在仍然完成的情况下完成保留我创建的 mirror/transparency 效果。
应用在这条线上崩溃:
Bitmap bitmapWithReflection = Bitmap.createBitmap(width
, (height + height/2), Config.ARGB_8888);
并且我尝试实现:
Bitmap reflectionImage = Bitmap.createScaledBitmap(originalImage, height/2, height/2, false);
然而,这是不正确的,导致了另一次致命的崩溃,在我的 logcat:
中没有任何价值
11-27 17:30:58.206: I/art(2111): Clamp target GC heap from 99MB to 96MB
11-27 17:31:01.354: I/Process(2111): Sending signal. PID: 2111 SIG: 9
11-27 17:31:42.609: I/Process(2235): Sending signal. PID: 2235 SIG: 9
如何避免这种情况?
Logcat:
11-27 17:26:00.490: D/AndroidRuntime(1953): Shutting down VM
11-27 17:26:00.492: E/AndroidRuntime(1953): FATAL EXCEPTION: main
11-27 17:26:00.492: E/AndroidRuntime(1953): Process: com.cb, PID: 1953
11-27 17:26:00.492: E/AndroidRuntime(1953): java.lang.OutOfMemoryError: Failed to allocate a 10898412 byte allocation with 1855424 free bytes and 1811KB until OOM
11-27 17:26:00.492: E/AndroidRuntime(1953): at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.graphics.Bitmap.nativeCreate(Native Method)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.graphics.Bitmap.createBitmap(Bitmap.java:812)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.graphics.Bitmap.createBitmap(Bitmap.java:789)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.graphics.Bitmap.createBitmap(Bitmap.java:756)
11-27 17:26:00.492: E/AndroidRuntime(1953): at com.cb.CoverFlowExample$ImageAdapter.createReflectedImages(CoverFlowExample.java:133)
11-27 17:26:00.492: E/AndroidRuntime(1953): at com.cb.CoverFlowExample.onCreate(CoverFlowExample.java:47)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.Activity.performCreate(Activity.java:5990)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.ActivityThread.access0(ActivityThread.java:151)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.os.Handler.dispatchMessage(Handler.java:102)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.os.Looper.loop(Looper.java:135)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.ActivityThread.main(ActivityThread.java:5254)
11-27 17:26:00.492: E/AndroidRuntime(1953): at java.lang.reflect.Method.invoke(Native Method)
11-27 17:26:00.492: E/AndroidRuntime(1953): at java.lang.reflect.Method.invoke(Method.java:372)
11-27 17:26:00.492: E/AndroidRuntime(1953): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
11-27 17:26:00.492: E/AndroidRuntime(1953): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
11-27 17:26:04.564: I/Process(1953): Sending signal. PID: 1953 SIG: 9
来源:
int index = 0;
for (int imageId : mImageIds) {
Bitmap originalImage = BitmapFactory.decodeResource(getResources(),
imageId);
int width = originalImage.getWidth();
int height = originalImage.getHeight();
//This will not scale but will flip on the Y axis
Matrix matrix = new Matrix();
matrix.preScale(1, -1);
//Create a Bitmap with the flip matrix applied to it.
//We only want the bottom half of the image
Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height/2, width, height/2, matrix, false);
//Create a new bitmap with same width but taller to fit reflection
Bitmap bitmapWithReflection = Bitmap.createBitmap(width
, (height + height/2), Config.ARGB_8888);
//Create a new Canvas with the bitmap that's big enough for
//the image plus gap plus reflection
Canvas canvas = new Canvas(bitmapWithReflection);
//Draw in the original image
canvas.drawBitmap(originalImage, 0, 0, null);
//Draw in the gap
Paint deafaultPaint = new Paint();
canvas.drawRect(0, height, width, height + reflectionGap, deafaultPaint);
//Draw in the reflection
canvas.drawBitmap(reflectionImage,0, height + reflectionGap, null);
//Create a shader that is a linear gradient that covers the reflection
Paint paint = new Paint();
LinearGradient shader = new LinearGradient(0, originalImage.getHeight(), 0,
bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 0x00ffffff,
TileMode.CLAMP);
//Set the paint to use this shader (linear gradient)
paint.setShader(shader);
//Set the Transfer mode to be porter duff and destination in
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
//Draw a rectangle using the paint with our linear gradient
canvas.drawRect(0, height, width,
bitmapWithReflection.getHeight() + reflectionGap, paint);
ImageView imageView = new ImageView(mContext);
imageView.setImageBitmap(bitmapWithReflection);
imageView.setLayoutParams(new CoverFlow.LayoutParams(1900, 1500));
imageView.setScaleType(ScaleType.FIT_XY);
mImages[index++] = imageView;
}
return true;
}
缩放图像的最基本版本是指定样本大小。或者换句话说,告诉位图解码器只解码每第 n 个像素和行。所以 2 表示如果原始图像为 1000x1000,则它仅加载 500x500,这意味着内存减少了 4。
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
int index = 0;
for (int imageId : mImageIds) {
Bitmap originalImage = BitmapFactory.decodeResource(getResources(),
imageId, options);
这可能还不够,具体取决于大小、您使用的图像、phone 和其他几个因素。这里有一篇文章
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
解释了最重要的部分。
我正在尝试执行一些内存管理,看来我需要先缩放图像才能使用它 - 问题是 - 我不确定如何在仍然完成的情况下完成保留我创建的 mirror/transparency 效果。
应用在这条线上崩溃:
Bitmap bitmapWithReflection = Bitmap.createBitmap(width
, (height + height/2), Config.ARGB_8888);
并且我尝试实现:
Bitmap reflectionImage = Bitmap.createScaledBitmap(originalImage, height/2, height/2, false);
然而,这是不正确的,导致了另一次致命的崩溃,在我的 logcat:
中没有任何价值 11-27 17:30:58.206: I/art(2111): Clamp target GC heap from 99MB to 96MB
11-27 17:31:01.354: I/Process(2111): Sending signal. PID: 2111 SIG: 9
11-27 17:31:42.609: I/Process(2235): Sending signal. PID: 2235 SIG: 9
如何避免这种情况?
Logcat:
11-27 17:26:00.490: D/AndroidRuntime(1953): Shutting down VM
11-27 17:26:00.492: E/AndroidRuntime(1953): FATAL EXCEPTION: main
11-27 17:26:00.492: E/AndroidRuntime(1953): Process: com.cb, PID: 1953
11-27 17:26:00.492: E/AndroidRuntime(1953): java.lang.OutOfMemoryError: Failed to allocate a 10898412 byte allocation with 1855424 free bytes and 1811KB until OOM
11-27 17:26:00.492: E/AndroidRuntime(1953): at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.graphics.Bitmap.nativeCreate(Native Method)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.graphics.Bitmap.createBitmap(Bitmap.java:812)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.graphics.Bitmap.createBitmap(Bitmap.java:789)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.graphics.Bitmap.createBitmap(Bitmap.java:756)
11-27 17:26:00.492: E/AndroidRuntime(1953): at com.cb.CoverFlowExample$ImageAdapter.createReflectedImages(CoverFlowExample.java:133)
11-27 17:26:00.492: E/AndroidRuntime(1953): at com.cb.CoverFlowExample.onCreate(CoverFlowExample.java:47)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.Activity.performCreate(Activity.java:5990)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.ActivityThread.access0(ActivityThread.java:151)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.os.Handler.dispatchMessage(Handler.java:102)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.os.Looper.loop(Looper.java:135)
11-27 17:26:00.492: E/AndroidRuntime(1953): at android.app.ActivityThread.main(ActivityThread.java:5254)
11-27 17:26:00.492: E/AndroidRuntime(1953): at java.lang.reflect.Method.invoke(Native Method)
11-27 17:26:00.492: E/AndroidRuntime(1953): at java.lang.reflect.Method.invoke(Method.java:372)
11-27 17:26:00.492: E/AndroidRuntime(1953): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
11-27 17:26:00.492: E/AndroidRuntime(1953): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
11-27 17:26:04.564: I/Process(1953): Sending signal. PID: 1953 SIG: 9
来源:
int index = 0;
for (int imageId : mImageIds) {
Bitmap originalImage = BitmapFactory.decodeResource(getResources(),
imageId);
int width = originalImage.getWidth();
int height = originalImage.getHeight();
//This will not scale but will flip on the Y axis
Matrix matrix = new Matrix();
matrix.preScale(1, -1);
//Create a Bitmap with the flip matrix applied to it.
//We only want the bottom half of the image
Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height/2, width, height/2, matrix, false);
//Create a new bitmap with same width but taller to fit reflection
Bitmap bitmapWithReflection = Bitmap.createBitmap(width
, (height + height/2), Config.ARGB_8888);
//Create a new Canvas with the bitmap that's big enough for
//the image plus gap plus reflection
Canvas canvas = new Canvas(bitmapWithReflection);
//Draw in the original image
canvas.drawBitmap(originalImage, 0, 0, null);
//Draw in the gap
Paint deafaultPaint = new Paint();
canvas.drawRect(0, height, width, height + reflectionGap, deafaultPaint);
//Draw in the reflection
canvas.drawBitmap(reflectionImage,0, height + reflectionGap, null);
//Create a shader that is a linear gradient that covers the reflection
Paint paint = new Paint();
LinearGradient shader = new LinearGradient(0, originalImage.getHeight(), 0,
bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 0x00ffffff,
TileMode.CLAMP);
//Set the paint to use this shader (linear gradient)
paint.setShader(shader);
//Set the Transfer mode to be porter duff and destination in
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
//Draw a rectangle using the paint with our linear gradient
canvas.drawRect(0, height, width,
bitmapWithReflection.getHeight() + reflectionGap, paint);
ImageView imageView = new ImageView(mContext);
imageView.setImageBitmap(bitmapWithReflection);
imageView.setLayoutParams(new CoverFlow.LayoutParams(1900, 1500));
imageView.setScaleType(ScaleType.FIT_XY);
mImages[index++] = imageView;
}
return true;
}
缩放图像的最基本版本是指定样本大小。或者换句话说,告诉位图解码器只解码每第 n 个像素和行。所以 2 表示如果原始图像为 1000x1000,则它仅加载 500x500,这意味着内存减少了 4。
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
int index = 0;
for (int imageId : mImageIds) {
Bitmap originalImage = BitmapFactory.decodeResource(getResources(),
imageId, options);
这可能还不够,具体取决于大小、您使用的图像、phone 和其他几个因素。这里有一篇文章
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
解释了最重要的部分。