Android で画像を読み込むのは結構厄介。一つの ImageView に読み込むならそんなに悩まないけど、 ListView やら GridView やらで画像を扱うとすぐ OutOfMemory って怒られる。限られた資源、守りたいですね。
基本は BitmapFactory.Options.inJustDecodeBounds = true にして、画像の情報だけを とって BitmapFactory.Options.inSampleSize を適切にしてあげて全体を無難に読み込む。そうじゃなくて、大きな画像の一部を切り抜いてもいいんじゃないかと。そんな画像切り抜き BitmapRegionDecoder クラスというのがあります。
とりあえず
サンプルは Github に上げた。
読み込み
画像の読み込みはバックグラウンドで行うのが基本。AsyncTaskLoader で行なっている。
例では assets にある画像ファイルを読み込んで表示しようとしています。読み込んだ画像よりも Rect のサイズが大きいと例外になると思いきや、はみ出した部分は真っ黒で塗りつぶされた画像が出来上がる。綺麗にやろうとしたらちゃんとサイズを見たほうがいいと思う。
そもそも画像をくり抜こうとしたら Bitmap 作って そこから Canvas 作って Rect 作ってと・・・意外にめんどい。しかも メモリ節約のために小さく切り抜くのにあたらに Bitmap 作るなんて本末転倒。そこはさくっと BitmapRegionDecoder で仕上げるのが吉。
ただし、BitmapRegionDecoder は API Level 10 以上。Froyo[1] Gingerbread (API Level 9, < Android OS 2.3.3) には対応していません。Android OS 1.6, 2.2 以上がターゲットのアプリには使えないことになります。 まあ、今なら Gingerbread (API Level 10, >= Android OS 2.3.3)もしくは ICS 以降をターゲットにするでしょうから、全く問題ない範囲だと思います。
そもそも画像をくり抜こうとしたら Bitmap 作って そこから Canvas 作って Rect 作ってと・・・意外にめんどい。しかも メモリ節約のために小さく切り抜くのにあたらに Bitmap 作るなんて本末転倒。そこはさくっと BitmapRegionDecoder で仕上げるのが吉。
ただし、BitmapRegionDecoder は API Level 10 以上。
無駄にハマったこと
BitmapFactory.Options.inJustDecodeBounds = true で必要な InputStream と BitmapFactory.Options.inJustDecodeBounds = false で実際に読み込む時の InputStream。同じ物を使いまわすとデコードできません。BitmapRegionDecoder#decodeRegion() の場合は
java.io.IOException: Image format not supportedの IOException が出ます。IOException でそのメッセージですか、そうですか・・・。InputStream は別個に作成しましょう。