背景
ブラー効果の流行
最近はアプリでブラー効果をよく見ます。
ブラー効果を使う理由は、次のようなものだと思います。
- 背景をぼかすことで、その上の文字や画像に注目させたい
- 没入感を高める(奥行きを出す)
また注目の対象が画像の場合、それにブラーをかけたものを背景にするのをよく見ます。
アプリでブラーをかける懸念
一般的に画像処理は重いものです。
そのためブラー処理をアプリで実装すると以下ような懸念があります。
- 端末のメモリ不足
- パフォーマンス低下
古い端末だとメモリ不足で処理ができないケースがあります。
サイズが大きい画像の処理ではそれだけメモリが必要になりますが、メモリ不足になるとアプリがクラッシュします。
またメモリ不足にならなくても、処理に時間がかかります。
それがメインスレッドで処理された場合はアプリが固まり、ユーザにストレスを与えてしまいます。
安全にブラーをかける方法を考えよう
Androidの端末はピンキリなので、上記の懸念に向き合う必要があります。
ただ大変なので、アプリでブラー処理をしないアプローチもあります。(後述)
でも安全なブラー処理ができるなら、UIが良くなり、アプリの競争力向上につながるはずです。
ブラーをかける方法
Compose
ライブラリ
- glide-transformations
- 画像読み込みライブラリ Glide 向け
BlurTransformation
を利用する
Modifier.blur()
(Android 12 以上)
AndroidView
ライブラリ
- glide-transformations
- 画像読み込みライブラリ Glide 向け
BlurTransformation
を利用する
- Blurry
- RealtimeBlurView
- BlurKit
- BlurView
- renderscript-intrinsics-replacement-toolkit
- RenderScriptの代替
- RenderScript (Android 12 以降でサポート終了)
- RenderEffect
パフォーマンス計測
Jetpack Macrobenchmark
の FrameTimingMetric
を計測する。
テストコード: BlurBenchmark.kt
- frameDurationCpuMs
- フレームの生成にかかった時間
- フレーム間の時間は60fps → 16.67ms、90fps → 11.12msなので、これより短くなければフレーム落ちする。
- frameOverrunMs (API 29以上)
- 正の値 → どれくらいの時間フレームの生成が遅れたか
- 負の値 → どれくらいの時間フレームの生成が早かったか
計測結果
テスト環境
- Pixel 7
- Galaxy J5
計測結果の見方
- frameDurationCpuMsのP95の列で降順ソート
- frameDurationCpuMs
- 16.67ms以上なら赤色
- 11.11ms以上なら黄色
- frameOverrunMs
- 負の値なら青色
Pixel 7 の計測結果
Galaxy J5 の計測結果
比較検討
全体的にAndroidViewが早いので、フルComposeでなければAndroidViewを選択するのが良さそうです。
Composeが良ければ、glide-transformations を使うのが、 Modifier.blur()
より良さそうです。
さらに選択肢を精査するためには、以下の観点で比較します。
- メンテナンスのしやすさ
- パフォーマンス
メンテナンスのしやすさ
メンテナンスしづらくなる要素には以下のようなものがあります。
それぞれ比較してみたのが以下の表です。
ここであげたライブラリは全て非推奨のRenderScriptを利用しています。
そのため将来的にRenderScriptから移行が必要になった時に、ライブラリの更新を待つか、自前で実装したものに置き換える必要が出てきます。
パフォーマンス
非推奨のRenderScriptを利用しない方法は以下に絞られました。
- AndroidView | renderscript-intrinsics-replacement-toolkit
- AndroidView | RenderEffect(Android 12以上)
- Compose | Modifier.blur()(Android 12以上)
Modifier.blur() はフレーム落ちが多いので、あまり使いたくありません。
AndroidViewの2つの方法は、どちらも同等のパフォーマンスです。
ちなみに公式ドキュメントには以下の記載がありました。
Android 12(API レベル 31)以降を対象としている場合は、Toolkit.blur() ではなく RenderEffect クラスを使用することをおすすめします。
https://developer.android.com/guide/topics/renderscript/migrate?hl=ja
どの方法を使うか
ここまでの比較で、以下の方法が良いと思いました。
- Android 12 以上
- AndroidView + RenderEffect で自前実装
- Android 12 未満
- AndroidView + renderscript-intrinsics-replacement-toolkit で自前実装
パフォーマンスと安全性を上げる
TODO