使用Picasso和自定义Transform对象加载大图像

时间:2014-05-19 14:25:46

标签: android picasso

我在加载"大"时使用Picasso获得Out Of Memory异常。来自Android Gallery的图像(> 1.5MB)(使用startActivityForResult)。

我使用自定义Target对象,因为我需要在Bitmap准备就绪时对其进行预处理,并且我还使用自定义Transform对象来缩放Bitmap。

问题是我的Transform对象上的方法public Bitmap transform(Bitmap source)从未被调用,因为Out of Memory Exception,所以我没有机会重新采样图像。

但是,如果我使用.resize(maxWidth, maxHeight)方法,那么它会加载图像OK。我认为Transform对象也是出于这个目的,但似乎在调整大小后调用transform方法,如果我不调用resize,那么它将以Out of Memory结束。

问题是,调整大小时我需要指定宽度和高度,但我需要缩放并保持宽高比。

考虑图像将从用户图库中选择,因此它们可以更大或更小,纵向,平方或横向等,因此我需要自己的Transformation对象来执行需要我的应用程序的逻辑。

2 个答案:

答案 0 :(得分:59)

我找到了解决方案..

在我的Transform对象中,我需要将图像(保持纵横比)缩放到1024 x 768 max。

除非我调用.resize(width, height)对图像进行重新取样,否则永远不会调用变换对象。

为了保持宽高比并使用调整大小,我拨打.centerInside()。这样,图像将被缩放重新采样以适合宽度,高度)。

我给.resize(宽度,高度)的值是Math.ceil(Math.sqrt(1024 * 768))。 通过这种方式,我确保图像的自定义变换对象更高,并且还可以避免内存异常

更新:完整示例

按照这个例子,你会得到一个适合MAX_WIDTH和MAX_HEIGHT界限的图像(保持纵横比)

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类:

import android.graphics.Bitmap;
import com.squareup.picasso.Transformation;

/**
 * Transformate the loaded image to avoid OutOfMemoryException
 */
public class BitmapTransform implements Transformation {

    private final int maxWidth;
    private final 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;
    }

}

答案 1 :(得分:2)

在Android开发者网站上有一篇非常好的文章,当我在加载大图片时遇到同样的问题时,它帮了我很多。

This文章解释了导致错误的原因以及如何解决错误。还有其他文章(参见菜单),例如,缓存图像。