ギークに憧れて

技術ネタはQiitaで http://qiita.com/hotchemi

画像ライブラリPicassoの使い方

Jake Wharton率いるSquareが開発したAndroidの画像ダウンロードやキャッシュを「良い感じに」やってくれるライブラリ。

同等の事を実現するライブラリにはUniversal Image LoaderVolleyのImageLoader等があるが,開発の活発さや導入コスト,サポート体制等も含めてSquareが管理しているものが一番モダンで信頼が置けるだろうとみた。

Universal Image Loaderは詳細な設定オプションがあり便利だが、実装が一部冗長な為,Picassoの方がユーザーフレンドリーな印象を持ちました。が,状況に応じて使い分けるでもいいかも。

仕事で使う為にキャッシュの詳細な仕様やよく使うメソッドについて知見をまとめた。

Picassoの良い所

  • Adapter内でのImageViewのリサイクルやダウンロード処理のキャンセルを自動で実行してくれる
  • 複雑な画像の変形処理を最小のメモリ消費で実現できる
  • 自動でメモリ・ファイルキャッシュをやってくれる

Download

<dependency>
  <groupId>com.squareup.picasso</groupId>
  <artifactId>picasso</artifactId>
  <version>2.3.3</version>
</dependency>
compile 'com.squareup.picasso:picasso:2.3.3'

Usage

公式ドキュメントに書いてるある様に,大体の場合1行で書く事ができる。

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

Picasso#withメソッドでデフォルト値が設定されたPicassoインスタンスを生成している。内部ではPicasso#Builderクラスのbuildメソッドがcallされている。

public static Picasso with(Context context) {
  if (singleton == null) {
    synchronized (Picasso.class) {
      if (singleton == null) {
        singleton = new Builder(context).build();
      }
    }
  }
  return singleton;
}

キャッシュ

Javadocにもあるが,withでインスタンスを生成した時のキャッシュ仕様は下記の通り。

メモリキャッシュ

  • アプリで利用可能なRAMのうち15%を使用する。
  static int calculateMemoryCacheSize(Context context) {
    ActivityManager am = getService(context, ACTIVITY_SERVICE);
    boolean largeHeap = (context.getApplicationInfo().flags & FLAG_LARGE_HEAP) != 0;
    int memoryClass = am.getMemoryClass();
    if (largeHeap && SDK_INT >= HONEYCOMB) {
      memoryClass = ActivityManagerHoneycomb.getLargeMemoryClass(am);
    }
    // Target ~15% of the available heap.
    return 1024 * 1024 * memoryClass / 7;
  }

ディスクキャッシュ

  • ストレージのうち2%(5MB以上50MB)を自動で計算してくれる。ディスクキャッシュの期限はInteger.MAX_VALUEとなっている。

デフォルトだとAPI Levelが14以上でないとディスクキャッシュは有効にならない(内部でHttpResponseCacheを使用している為)。API Levelが14以下でディスクキャッシュを有効にする為には、Squareが独自開発しているOkHttpdependencyに組み込む。

 static long calculateDiskCacheSize(File dir) {
    long size = MIN_DISK_CACHE_SIZE;

    try {
      StatFs statFs = new StatFs(dir.getAbsolutePath());
      long available = ((long) statFs.getBlockCount()) * statFs.getBlockSize();
      // Target 2% of the total space.
      size = available / 50;
    } catch (IllegalArgumentException ignored) {
    }

    // Bound inside min/max size for disk cache.
    return Math.max(Math.min(size, MAX_DISK_CACHE_SIZE), MIN_DISK_CACHE_SIZE);
  }

自前の設定を差し込みたい場合はPiccaso#Builderクラスを利用してPicassoインスタンスを生成する。メモリキャッシュやファイルキャッシュの設定をいじりたい場合はDownloaderを実装したクラスを実装しBuilderに設定する。

スレッドプール

  • Three download threads for disk and network access.

    • PicassoExecutorServiceを確認する事。ネットワークの状態によってスレッドプールの数を変更している。

よく使うメソッド

画像を都度柔軟に変更できるのがPicassoの強みで,提供されているメソッドはRequestCreatorクラスに生えている。よく使うものをピックアップした。

placeholder(int placeholderResId)

読み込み中の画像を設定する事ができる

error(int errorResId)

画像取得失敗時のメソッドを設定できる

into(Imageview imageview)

ImageView等を指定し、リクエストした画像を当て込む先を指定する。

centerCrop()

resizeメソッドによって指定された境界でアスペクト比を保ったまま切り取る。

centerInside()

resizeメソッドによって指定された境界でアスペクト比を保ったまま画像全てを表示。

fit()

指定したImageVIewの境界に合わせてresizeを実行してくれる。resizeメソッドと併用する事はできない。

resize(int targetWidth, int targetHeight)

指定したsize(px)で画像をリサイズする。

resizeDimen(int targetWidthResId, int targetHeightResId)

resizeと同じだが、dimes.xmlに指定したdpでリサイズを実行できる

rotate(float degrees)

画像を回転させる。

transform(Transformation transformation)

上記以外で画像の変形処理を自前で実装したい場合は、自前のTransformationを実装して設定してあげる。

public class CropSquareTransformation implements Transformation {
  @Override public Bitmap transform(Bitmap source) {
    int size = Math.min(source.getWidth(), source.getHeight());
    int x = (source.getWidth() - size) / 2;
    int y = (source.getHeight() - size) / 2;
    Bitmap result = Bitmap.createBitmap(source, x, y, size, size);
    if (result != source) {
      source.recycle();
    }
    return result;
  }

  @Override public String key() { return "square()"; }
}

noFade()

デフォルトで実行されるフェードインを無効にする

リソース読み込み

Resources, assets, files, content providers等の画像形式に対応している。

Picasso.with(context).load(R.drawable.landing_screen).into(imageView1);
Picasso.with(context).load(new File(...)).into(imageView2);

デバッグ

Picassoデバッグすら気が利いている。

  • setLoggingEnabled(true)する事で詳細なログが出力される。

  • setIndicatorsEnabled(true)する事で、読み込まれた画像がネット、メモリ、ファイルキャッシュのどこから来たのか判定する事ができる。

Document

javadocや専用のstackoverflowまであるのは嬉しい。

公式

Javadoc

StackOverFlow