メモです
setImageResource()が極端に重くなる。
android:largeHeap="true"
は元々指定されていた。
リソースの置き場を確認
画像のスケーリングが処理としてはかなり重いので適切な場所に画像リソースを置いておかないとメモリを消費しがち。
drawable-XXdpi
にサイズごとに分けて置くか、-nodpi, -anydpiといったところに配置してスケーリングが発生しないようにする。
https://developer.android.com/training/multiscreen/screendensities
画像を解放して続行
重くなる処理がわかっているのでcatchして発生後の処理を書くことができる。
下の例では重い画像を解放してやって続行している。アニメーションは表示させないことになる。
OOMが実際に出るまでに数秒は重くて操作できない時間が発生する。
処理が続行した直後に別の画像の読み込みに失敗することがある。
もちろん推奨はできないけどAndroidCodeSearchで検索すると割とヒットしたりするやり方。
OutOfMemoryErrorはExceptionを継承したクラスではないのでExceptionでまとめてcatchしようとしてもできない
try {
imageView.setImageResource(animatable)
} catch(e: OutOfMemoryError) {
imageView.setImageDrawable(null)
return
}
自作FrameAnimationクラスを作る
先達が数人いたのでそれらを参考に。別記事にまとめます。
https://stackoverflow.com/questions/8692328/causing-outofmemoryerror-in-frame-by-frame-animation-in-android
https://gist.github.com/miensol/f4d6aa65fb09d627ae7e
自作アプリの中でいい感じにデコードする処理の詳細↓
https://developer.android.com/topic/performance/graphics/load-bitmap
試してうまくいかなかったこと
lowMemory検知
https://developer.android.com/topic/performance/memory#CheckHowMuchMemory
このへん
今回のケースではアニメーションの読み込み開始まではメモリ消費してないのでlowMemoryではfalseが返ってくるため回避不可だった。
空きメモリ量を取得して確認
OOMErrorのFatalログに確保しようとして失敗したメモリ量が出力されるので確認は可能なはず?
取得の仕方や取得できるメモリ情報にもいろいろあるらしくどれで判定したらいいかよくわからず。ちゃんと調べたら追記するか別記事にまとめます。
感想・その他
ハイエンド端末でも試験する方法が用意されていた
https://developer.android.com/topic/performance/memory-overview#stressapptest