我发现了一个用出毕加索内存异常从Android的画廊(使用startActivityForResult)装载大的图像(> 1.5MB)时。
I'm getting an Out Of Memory exception using Picasso when loading "large" images (> 1.5MB) from Android Gallery (using startActivityForResult).
我使用的是自定义的目标对象,因为我需要preprocess位图时,它已准备就绪,也是我使用的是自定义转换对象缩放位图。
I'm using a custom Target object because I need to preprocess the Bitmap when it is ready and also I'm using a custom Transform object to scale the Bitmap.
问题是,公共位图转换(位图源)
我的Transform对象的方法不会被调用,因为内存不够的异常,所以我没有得到的oportunity重新采样的图像。
The problem is that the method public Bitmap transform(Bitmap source)
on my Transform object is never called because the Out Of Memory Exception, so I don't get the oportunity to resample the image.
但是,如果我用 .resize(了maxWidth,了maxHeight)
的方法,然后将其加载图像确定。我supossed该Transform对象是用于这一目的也一样,但似乎变换方法调整大小后调用,而且,如果我不叫调整,那么它会在内存中结束。
But, if I use the .resize(maxWidth, maxHeight)
method, then it loads the image OK. I supossed that the Transform object was for that purpose too, but it seems that the transform method is called after the resize, and, if I don't call resize, then it will end in an Out of Memory..
现在的问题是,随着调整大小我需要指定宽度和高度,但我需要扩展,并保持宽高比。
The problem is that with resize I need to specify both width and height, but I need to scale and keep the aspect ratio.
考虑到图像将从用户库中选择,这样他们就可以更大或更小,肖像,平方或风景等,所以我需要我自己的转型目标来执行,需要我的应用程序的逻辑。
Consider that the images will be selected from user Gallery, so they can be bigger or smaller, portrait, squared or landscape, etc, so I need my own Transformation object to perform the logic that needs my application.
我找到了解决办法。
在我的Transform对象,我需要将图像缩放(保持纵横比)为1024 x 768最大。
In my Transform object I needed to scale the image (keeping aspect ratio) to 1024 x 768 max.
变换对象从来没有被执行,除非我称之为 .resize(宽,高)
重新取样下来的图像。
Transform object was never called unless I call .resize(width, height)
to resample down the image.
有关保持纵横比和使用调整我称之为 .centerInside()
。这样图像进行调整重新取样,以适应宽,高)。
For keeping aspect ratio and using resize I call .centerInside()
. This way image will be scaled resample to fit width, height).
这是我给.resize(宽,高)的值是 Math.ceil(的Math.sqrt(1024 * 768))
。
这样,我敢肯定有一个形象的我的自定义不够高Transform对象,又可以避免内存溢出异常
The value that I give to .resize(width, height) is Math.ceil(Math.sqrt(1024 * 768))
.
This way I'm sure to have an image higher enough for my custom Transform object, and also avoid Out Of Memory exception
更新:完整的示例
下面这个例子,你会得到一个适合MAX_WIDTH和MAX_HEIGHT范围内的图像(保持纵横比)
Following this example you will get a image that fits inside MAX_WIDTH and MAX_HEIGHT bounds (keeping aspect ratio)
private static final int MAX_WIDTH = 1024;
private static final int MAX_HEIGHT = 768;
int size = (int) Math.ceil(Math.sqrt(MAX_WIDTH * MAX_HEIGHT));
// Loads given image
Picasso.with(imageView.getContext())
.load(imagePath)
.transform(new BitmapTransform(MAX_WIDTH, MAX_HEIGHT))
.skipMemoryCache()
.resize(size, size)
.centerInside()
.into(imageView);
这是我的自定义BitmapTransform类:
And this is my custom BitmapTransform class:
import android.graphics.Bitmap;
import com.squareup.picasso.Transformation;
/**
* Transformate the loaded image to avoid OutOfMemoryException
*/
public class BitmapTransform implements Transformation {
int maxWidth;
int maxHeight;
public BitmapTransform(int maxWidth, int maxHeight) {
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
}
@Override
public Bitmap transform(Bitmap source) {
int targetWidth, targetHeight;
double aspectRatio;
if (source.getWidth() > source.getHeight()) {
targetWidth = maxWidth;
aspectRatio = (double) source.getHeight() / (double) source.getWidth();
targetHeight = (int) (targetWidth * aspectRatio);
} else {
targetHeight = maxHeight;
aspectRatio = (double) source.getWidth() / (double) source.getHeight();
targetWidth = (int) (targetHeight * aspectRatio);
}
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source) {
source.recycle();
}
return result;
}
@Override
public String key() {
return maxWidth + "x" + maxHeight;
}
};