Google Developers YouTubeチャンネルに、Androidの性能パターンに関する16の動画がポストされている。これらの動画は、開発者がAndroidアプリを開発するときに直面する多くの性能問題について概括しており、アドバイスもしている。この記事ではそのアドバイスを簡単に紹介したいと思う。
Rendering Performance 101と題した動画では、Colt McAnlis氏が、描画について、Androidで最も性能問題がおきやすいと説明している。あるアクティビティが次のフレームを画面に描画するのを準備するのに16ミリ秒以上必要な場合、システムはそれぞれのフレーム表示を落とす。フレームが落ちると、ユーザは不快な操作をせざるを得ない。
描画の性能問題の原因は以下の通り。巨大なビューの階層構造を再描画しようとしている。多くのオブジェクトを描画する。アニメーションの繰り返し。氏はこのような問題を調査するために、いくつかのツールを使うことを薦めている。Hierarchy Viewer、Traceview、Profile GPU Rendering、Debug GPU Overdraw、GPU View Updatesなどだ。
また、描画処理とレイアウトを最小限にするのも推奨されている。描画処理については、Developer Option Show GPU View Updatesで確認できる。レイアウトはHierarchy Viewerで調べられる。
Overdrawはひとつのフレームである特定のピクセルが何度描画されたのかカウントされる。このカウンターは1であることが望ましいのだが、常に1にしておくのは不可能だ。Debug GPU Overdrawを使うと最も描画が多い部分を見つけ、何らかの改善ができる。
VSYNC。開発者はフレームレートの変化に注意を払う必要がある。特にあるフレームレートが画面のリフレッシュレートよりも高い場合、アニメーションにユーザがわかるようなラグが生まれてしまう。
Profile GPU Rendering。Developer Optionsの設定をすると、このツールで画面上でアクティブになっているAndroidのアクティビティをすべてグラフ化できる。このツールは、フレームレートが閾値である16ミリ秒以下になっているかどうか調べるのに便利だ。この性能グラフには、描画に関するすべての主要なアクティビティの時間情報が含まれている。リストの更新や表示、glSwapBuffersの処理などだ。
60FPS。望ましい秒間フレームレートは60FP。60FPSであれば、複雑なアニメーションも人間の目で認知できる。
Custom Views。onDraw()メソッドをカスタムビューを作るためにオーバーライドする場合、描画処理はAndroidの上書き描画の最適化の処理をスキップする。このスキップを最小化するために、カスタム描画をする領域を特定するためにcanvas.clipRect()を使うと良い。また、quickReject()を使えば、クリップした四角の外に領域があるかどうかを判定して、描画時間を節約できる。
メモリチェーン。あとで破棄する、たくさんの小さなメモリオブジェクトのために繰り返しメモリを確保するとガーベッジコレクタが複数回動いてしまい、16ミリ秒以上の時間がかかり、フレームが落ちてしまう。Android StudioのMemory Monitorを使うことで、GCの動きを視覚的に把握し、GCが発生しすぎているかどうか調べられる。Allocation Trackerはメモリオブジェクトがどこから来たのかを把握するのに使える。関連するコードを修正するとある程度メモリの確保を回避できるかもしれない。また、オブジェクトはonDraw()の内側で確保するべきではない。このメソッドは秒間何回も呼ばれるからだ。もし、アプリケーションが短期間で破棄されるオブジェクトが大量に必要であるなら、オブジェクトのプールを一度作成し、それを使い回すことで、GCを回避するのがいいだろう。
メモリリーク。メモリリークによってGCが終わるまでにかかる時間が長くなり、フレームレートに影響が出る。Androidのアクティビティがメモリリークを起こさないようにするために、ほとんどメモリを消費しない空のアクティビティを作成して、そこに遷移するようにして強制的にGCを走らせる。その空のアクティビティに遷移する前と後でAndroid StudioのAllocation Trackerを使ってメモリの利用を調べることで、アクティビティがメモリのリークを起こしているかどうかを判断できる。
バッテリー消費。パデュー大学とMicrosoft Researchの研究(PDF)によれば、いくつかの目立つアプリのバッテリーの70%がサードパーティの広告モジュールで使用されている。そのようなモジュールはデータの分析や位置の検出、広告のダウンロードを行っている。実際のアプリケーションの動きで使われるのは残りの30%だ。Googleは開発者にバッテリーの使用に注意を払うようアドバイスしている。ユーザの最大の関心事項だからだ。最も推奨されるのは、必要なとき以外はデバイスをスリープ状態のままにしておくことだ。スリープ状態から起動するときはWakeLockをタイムアウトなしで使い、アプリに何か問題があったら、スリープに戻るようにしておく。また、AlarmManager.setInexactRepeating()を使って、起動と他のアクティビティを一緒にしてバッテリーを節約する方法も考えられる。
バッテリーの使用は、デバイスが充電器に接続されているときやWiFiに繋がっているときに遅らせることで緩和できる。また、デバイスが起動するときに処理をまとめるのも有効だ。JobScheduler APIを使ってジョブを遅らせることで実現できる。また、ネットワーク接続に注意を払うのも有効だ。というのは、ネットワークにリクエストを送り、レスポンスを受けた後、デバイスは最低でも5秒は起動を続けるからだ。単に、サーバから追加のパケットが届くのを待つためだ。
McAnlis氏はSettings|Batteryで確認できるバッテリー利用の詳細とバッテリー履歴を活用して、アプリがどの程度バッテリーを使用しているか確かめることを推奨している。