🖼️

【Android】Picasso の Canvas: trying to draw too large bitmap の対処法

2022/07/06に公開

Picasso でサイズが大きい画像を扱うと、Canvas: trying to draw too large(121114048bytes) bitmapというエラーが発生することがありますが、このようなときは画像をリサイズします。

resize(width, height)

指定したwidth / heightのピクセルサイズで画像をリサイズします。

RequestCreator.java

// Resize the image to the specified size in pixels.
public RequestCreator resize(int targetWidth, int targetHeight) {
    data.resize(targetWidth, targetHeight);
    return this;
}

実装方法

Picasso.get()
    .load(url)
    .resize(width, height)
    .into(imageView)

resize(width, height)に、onlyScaleDown()を付けると、読み込む画像のサイズがresizeに指定したwidth / heightを超えた場合にのみリサイズされるようになります。

RequestCreator.java

// Only resize an image if the original image size is bigger than the target size specified by resize(int, int).
public RequestCreator onlyScaleDown() {
    data.onlyScaleDown();
    return this;
}

実装方法

Picasso.get()
    .load(url)
    .resize(width, height)
    .onlyScaleDown()
    .into(imageView)

fit()

fit()は、画像をセットするImageViewのサイズに合わせて、画像をリサイズしてくれます。

内部でImageViewのサイズを取得するためにViewTreeObserverを使用しているので、ImageViewがレイアウトされるまでリクエストが遅延するようになっています。

RequestCreator.java

// Attempt to resize the image to fit exactly into the target ImageView's bounds. 
// This will result in delayed execution of the request until the ImageView has been laid out.
// Note: This method works only when your target is an ImageView.
public RequestCreator fit() {
    deferred = true;
    return this;
}

public void into(ImageView target, Callback callback) {
    ...
    if (deferred) {
      if (data.hasSize()) {
        throw new IllegalStateException("Fit cannot be used with resize.");
      }
      int width = target.getWidth();
      int height = target.getHeight();
      if (width == 0 || height == 0) {
        if (setPlaceholder) {
          setPlaceholder(target, getPlaceholderDrawable());
        }
	// ImageViewのサイズが確定していない場合、DeferredRequest内で
	// view.getViewTreeObserver()を呼び出し、画像サイズを確定させてから
	// 再度into(ImageView, Callback)を呼び出している
        picasso.defer(target, new DeferredRequestCreator(this, target, callback));
        return;
      }
      // ImageViewのサイズにリサイズ
      data.resize(width, height);
    }

How to use

Picasso.get()
    .load(url)
    .fit()
    .into(imageView)

Discussion