Unmotivated

やる気はない

View のキャプチャを撮る

Android で View のキャプチャ画像を取得する方法を二種類紹介します。

どちらも UI スレッド以外のスレッドから呼び出し可能でした。

View の描画キャッシュを使用する方法

View の描画のためのキャッシュを利用する方法。

1
2
3
4
5
6
View view = findViewById(R.id.view);

view.setDrawingCacheEnabled(true);      // キャッシュを取得する設定にする
view.destroyDrawingCache();             // 既存のキャッシュをクリアする

Bitmap bmp = view.getDrawingCache();    // キャッシュを作成して取得する

描画キャッシュが有効になっているかどうかや、最新のキャッシュが存在するかどうかは状況によるので、自分で設定してやることで View のキャプチャを取得することができます。

Canvas に View を描画する方法

自分で用意した Canvas に View を描画する方法。

1
2
3
4
5
6
7
View view = findViewById(R.id.view);

Bitmap bmp = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Config.ARGB_8888);
                                        // view のサイズで Bitmap を作成
Canvas canvas = new Canvas(bmp);        // bmp をターゲットにした Canvas を作成

view.draw(canvas);                      // canvas に view を描画する

View のサイズで作った Bitmap を Canvas の書き込み先にし、draw() メソッドで書き込んでやることで、 View が描画された Bitmap を取得することができます。

[おまけ] getDrawingCache() まわりの豆知識

今までなんとなく使っていたけれど、View のキャプチャに buildDrawingCache() を必ず呼ぶようにしているスニペットがあったり、 getDrawingCache() で null が返ってくることがあったりと挙動を不審に思っていたので軽く調査(Android 4.2.2)。

  • 直前に setDrawingCacheEnabled(true) さえすれば、 getDrawingCache() の前に自分で buildDrawingCache() を呼ぶ必要はない
    • View のフラグに PFLAG_DRAWING_CACHE_ENABLED が立っていれば getDrawingCache() で buildDrawingCache() を呼んでいる
  • キャッシュを確実に更新したい場合は View を invalidate() するか destroyDrawingCache() でキャッシュをクリアする
    • フラグに PFLAG_DRAWING_CACHE_VALID が立っている、かつ DrawingCache が確保されていると buildDrawingCache() が呼ばれてもキャッシュが更新されない
    • invalidate() するだけだと Bitmap が recycle() されなそうなので、連打するとメモリ不足に陥るかも
  • setDrawingCacheEnabled() するだけでは destroyDrawingCache() が呼ばれないことがある
    • フラグが “変わった” ときだけ destroyDrawingCache() が呼ばれるようなので、オーバーヘッドも少ないし自分で destroyDrawingCache() を呼んだ方が無難そう
  • そもそも何に使われている “キャッシュ” なのか?
    • draw() 時に caching の条件を満たしていれば、 canvas に直接 drawBitmap() するために使われているので、まさに描画キャッシュのように見える
    • 条件については今回は追いきれず(LayerType や HardwareAccelerated など Android の描画周りの知識が足りなすぎた..)
    • ご存知の方がいたら教えて下さい!

Comments