こんにちは、Sleipnir Mobile for Android 開発担当の西田です。
今回は、Sleipnir Mobile for Android でも実施している Android アプリの描画チューニング手法を紹介します。
1.まずは計測 ~プロファイラ編~
古来より「計測なくして高速化なし」と言い伝えられています。まずは Android SDK 付属の Traceview というプロファイラで、遅いのは本当に描画なのかどうかを調べましょう。
プロファイリングの仕方ですが、開始/終了位置をコードで埋め込む方法と Eclipse から開始/終了を指示する方法があります。コードを埋め込む方法は、traceファイルをデバイスから取り出したりする必要がありちょっと面倒です。ですので今回は Eclipse からお手軽にプロファイリングする方法を紹介します。
まずはデバイス上で計測したい画面を表示します。次に下図赤丸のボタンをクリックしてプロファイリングの開始を指示します。その後デバイスで画面をグリグリ動かすなどして描画を十分に行わせてから同じボタンをクリックしてプロファイリングの終了を指示します。
すると Eclipse 上にプロファイリング結果の Traceview が自動的に表示されます。とてもお手軽ですね。
Traceview の見方は、 Traceview – グラフィカルログビューア – ソフトウェア技術ドキュメントを勝手に翻訳 が参考になります。
2.さらに計測 ~フレームレート編~
さて、1.での計測の結果、描画を高速化する必要があることがわかりました。が、高速化作業へ移る前に必要なモノがあります。それは「指標」です。指標がなければ成果は計れません。
指標はシンプルかつダイレクトが理想です。そこで指標としてフレームレート(FPS)を表示するようにしましょう。フレームレートとは 1 秒間に描画した回数のことです。LogCat に出力してもいいのですが、以下のビューをレイアウトに組み入れることでフレームレートを表示させることができます。
public class FpsTextView extends TextView { public static final int INTERVAL = 500; public static final int LIST_SIZE = 4; private long mTime = 0; private int mCount = 0; private LinkedList<Float> mFpsList = new LinkedList<Float>(); public FpsTextView(Context context) { this(context, null); } public FpsTextView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); long time = System.currentTimeMillis(); if (time - mTime >= INTERVAL) { final float fps = mCount * 1000 / (float) (time - mTime); mFpsList.offer(fps); while (mFpsList.size() > LIST_SIZE) { mFpsList.remove(); } mTime = time; mCount = 0; post(new Runnable() { @Override public void run() { Float[] fpss = mFpsList.toArray(new Float[0]); Arrays.sort(fpss); setText(String.format("%4.1f%n%4.1f", fpss[fpss.length - 1], fpss[0])); } }); } else { ++mCount; } } }
上記コードでは直近 4 回のフレームレートのうち、最高の値と最低の値を表示させるようにしています。重要なのは最高フレームレートで、ブレが少ないため指標として扱い易いです。
ちなみに Sleipnir Mobile for Android のデバッグ用パッケージでは常にこれを表示するようにしています。
3.不要な背景の塗りつぶしを抑制する
ところで皆様は Activity の背景が黒い理由をご存知でしょうか?それは黒で塗りつぶされているからです!
実はこれが結構な負荷になっています。ですので Activity がビューで覆いつくされている場合、以下のような手順で Activity 背景の塗りつぶしを抑制することで描画を高速化することができます。
まず、res/values/themes.xml で背景を塗りつぶさないテーマを定義します。
<resources> <style name="my_activity_theme" parent="android:Theme"> <item name="android:windowBackground">@null</item> </style> </resources>
次に AndroidManifest.xml で背景を塗りつぶさないテーマを Activity に適用します。
<activity android:name=".MyActivity" android:theme="@style/my_activity_theme" />
以上で Activity 背景の塗りつぶしを抑制できます。
参考: Android Developers Blog: Window Backgrounds & UI Speed
4. 半透明レイヤーの描画をキャッシュする
半透明の View を FrameLayout で重ねてレイヤーにすることは Android アプリ開発においてよくあることだと思います。しかし、スクロール可能なビューに複雑な半透明レイヤーを重ねたりすると、スクロールするたびにそのレイヤーも描画されることなり、これが描画のボトルネックになることがあります。
こういうときに効果があるのが、setDrawingCacheEnabled で半透明レイヤーの描画をキャッシュすることです。使い方は簡単で、半透明にしている View に対し、setDrawingCacheEnabled(true) を呼び出すだけです。
ただし、Android 3.0 以降でハードウェアアクセラレーションが有効な場合には効果がありませんので、ご注意下さい。
5. 最後に計測
最後に、高速化前と高速化後で指標であるフレームレートがどう変化しているかを確認しましょう。良い成果が得られるといいですね。
というわけで Android アプリを高速化する 5 ステップでした。計測の話が多くなってしまいましたが、それだけ重要ということでご容赦ください!皆様の Android アプリ開発に役立てて頂ければ幸いです。