Androidでの高速モバイルアプリケーションの開発。 パート2

Edisonでは、モバイルアプリケーションの最適化に頻繁に遭遇し、次の2つの問題のいずれかを解決する場合に非常に役立つと考えられる資料を共有したいと考えています。a)アプリケーションのスローダウンを少なくしたい。 b)大量のユーザーのために美しく、柔らかく、滑らかなインターフェースを作りたい。



Udi Cohenによる記事の翻訳の最初の部分に注目してください。これは、Android向けに最適化する若い同僚をトレーニングするためのガイドとして使用しました。



最初の部分を読む)







一般的なメモリのヒント



コードを記述するときに使用する簡単なガイドラインを次に示します。



GPUプロファイリング



Android Studio 1.4に新しく追加されたのは、GPUレンダリングプロファイリングです。

Androidウィンドウの下の[GPU]タブに移動すると、画面上の各フレームの取得にかかった時間を示すグラフが表示されます。



画像



グラフ上の各パネルは1つのレンダリングされたフレームを表し、色はプロセスのさまざまな段階を表します。





メジャー/レイアウト、入力処理など、より多くのステップを表示するために、より多くの色がマシュマロに追加されました。

画像



編集09/29/2015:GoogleのフレームワークエンジニアであるJohn Reckは、これらの色のいくつかについて次の情報を追加しました

「アニメーションという言葉の正確な定義は、CholebackerにCALLBACK_ANIMATIONとして登録されているすべてです。 これには、choreographer#postFrameCallbackおよびView#postOnAnimationが含まれます。これらは、view.animate()、ObjectAnimator、Transitionsなどで使用されます。そして、これはsystraceの「animation」ラベルと同じです。



「Misc」は、vsyncタイムスタンプと受信時の現在のタイムスタンプの間の遅延です。 Choreographerの「blabla ms skipping blabla ms skip by blablaフレーム」からのログを既に表示している場合は、「misc」として表示されます。 framestatsダンプ(https://developer.android.com/preview/testing/performance.html#timing-info)では、INTENDED_VSYNCとVSYNCに違いがあります。




ただし、この機能の使用を開始する前に、開発者のメニューでGPUレンダリングモードを有効にする必要があります。

画像



これにより、ツールはADBコマンドを使用して必要なすべての情報を取得できるようになります。



adb shell dumpsys gfxinfo <PACKAGE_NAME>
      
      







情報を得て、自分でチャートを作成できます。 このコマンドは、階層内の要素の数、すべての表示リストのサイズなどの有用な情報を表示します。 マシュマロでは、より多くの情報が得られます。



画像



アプリケーションのUIのテストを自動化した場合、特定のアクション(リストのスクロール、重いアニメーションなど)の後にこのコマンドを開始するアセンブリを作成し、「ジャンキーフレーム」などの値に時間の変化があるかどうかを確認できます。 これは、コードにいくつかの変更を加えた後のパフォーマンスヒットの判断に役立ち、アプリケーションが市場に出る前に問題を修正できます。 ここに示すように、「framestats」キーワードを使用すると、さらに正確な情報を取得できます



しかし、これがそのようなスケジュールを見る唯一の方法ではありません!



開発者のメニュー「GPUレンダリングのプロファイル」で見ることができるように、「画面上にバーとして」オプションもあります。 彼の選択により、画面上の各ウィンドウのグラフと、16 msのしきい値を示す緑色の線が表示されます。



画像



右側の例では、一部のフレームが緑の線を横切っていることがわかります。つまり、描画に16ms以上必要です。 青が支配しているように見えるため、描画する表現が多数あるか、複雑であることがわかります。 この場合、さまざまなタイプのビューをサポートするリボンをスクロールしています。 一部の要素は無効になり、一部は他の要素よりも複雑になります。 おそらく、いくつかのフレームがこの線を越えたのは、表示が難しい要素を捕らえたためでしょう。



階層ビューア



私はこのツールが大好きで、多くの人がこのツールを使用していないことを非常に残念に思っています!

Hierarchy Viewerを使用して、パフォーマンス統計を取得し、画面上で完全なビュー階層を表示し、要素のすべてのプロパティにアクセスできます。 また、すべてのトピックデータをダンプし、各スタイル属性に使用されているすべてのパラメーターを確認できますが、これは、階層ビューアーがAndroidモニターからではなくスタンドアロンで実行されている場合にのみ可能です。 アプリケーションレイアウトを作成し、それらを最適化する場合、このツールを使用します。



画像



中央には、ビューの階層を反映したツリーがあります。 プレゼンテーションの階層は広くなる可能性がありますが、深すぎる(〜10レベル)場合、多大なコストがかかる可能性があります。 ビューがView#onMeasure()で測定されるたびに、またはその子孫がView#onLayout()に配置されるとき、これらのコマンドはこれらのビューの子孫に同じように適用されます。 RelativeLayoutおよび一部のLinearLayout構成など、一部のレイアウトは各ステップを2回実行し、それらがネストされている場合、パスの数は指数関数的に増加します。



右下隅には、レイアウトの「計画」が表示され、各ビューの場所が示されます。 ここで、またはツリーでビューを選択して、左側のすべてのプロパティを確認できます。 レイアウトを設計するとき、特定のビューが終了する場所で終了する理由がわからないことがあります。 このツールを使用すると、ツリーを追跡して選択し、プレビューウィンドウのどこにあるかを確認できます。 画面上の表現の最終的な寸法を見て面白いアニメーションを作成し、この情報を使用して要素を正確に配置できます。 他のビューによって意図せずにブロックされた、失われたビューを見つけることができます。



画像



ビューごとに、レイアウトとそのすべての子孫の測定/作成/レンダリングに時間がかかりました。 色は、ツリー内の他の表現と比較して、これらの表現がどのように実行されるかを反映します;これは、弱いリンクを見つけるのに最適な方法です。 ビューのプレビューも表示されるので、ツリーを調べて、それらを作成する指示に従って、削除できる追加のステップを見つけることができます。 パフォーマンスに影響を与えるものの1つは、オーバードローと呼ばれます。



オーバードロー



GPUプロファイリングセクションでわかるように、GPUが多くの要素を描画する必要がある場合、グラフに黄色で表示される実行フェーズは完了するまでに時間がかかり、各フレームの描画に必要な時間が長くなります。 オーバードローは、赤い背景に黄色のボタンなど、何かの上に何かを描画するときに発生します。 GPUは、最初に赤い背景を描画し、次にその上に黄色のボタンを描画する必要があります。これにより、オーバードローが避けられなくなります。 オーバードローレイヤーが多すぎる場合、これがGPUがより集中的であり、16ミリ秒で十分な時間がない理由です。



画像



開発者のメニューの「GPU Overdrawのデバッグ」設定を使用すると、この領域でのオーバードローの程度を示すために、すべてのオーバードローが着色されます。 オーバードローの程度が1x / 2xであれば、それでも問題ありません。小さな赤い領域でもいいですが、画面上に赤の要素が多すぎる場合は、おそらく問題があります。 いくつかの例を見てみましょう。



画像



左側の例では、緑色のリストがありますが、これは通常は正常ですが、上部に画面を赤くするオーバードローがあり、これはすでに問題になっています。 右側の例では、リスト全体が明るい赤です。 両方の例には、2x / 3x度のオーバードローを持つ不透明なリストがあります。 これらは、ウィンドウ内の画面全体の背景色がアクティビティまたはフラグメントと重複している場合、およびリストビューとその各要素の表示にある場合に発生する可能性があります。



注:デフォルトのテーマは、ウィンドウ全体の背景色を設定します。 画面全体を覆う不透明なレイアウトのアクティビティがある場合、このウィンドウの背景を削除して、オーバードローレイヤーを1つ削除できます。 これは、トピックまたはコードでgetWindow()を呼び出すことで実行できます。onCreate()でSetBackgroundDrawable(null)を呼び出します。



階層ビューアを使用すると、すべての階層レイヤーをPSDファイルにエクスポートして、Photoshopで開くことができます。 さまざまなレイヤーを調査した結果、レイアウト内のすべてのオーバードローが明らかになります。 この情報を使用して、過剰なオーバードローを削除し、緑ではなく青を目指してください!



アルファ



透明度の使用はパフォーマンスに影響する可能性があります。その理由を理解するために、ビューでalphaパラメーターが設定されたときに何が起こるかを見てみましょう。 次の構造を考慮してください。



画像



互いにオーバーラップする3つのImageViewを含むレイアウトが表示されます。 直接実装では、setAlpha()でアルファを設定すると、すべての子孫ビュー(この場合はImageView)に伝搬するコマンドが呼び出されます。 次に、これらのImageViewは、フレームバッファーのalphaパラメーターで描画されます。 結果:



画像



これは私たちが見たいものではありません。



各ImageViewはアルファ値でレンダリングされたため、すべての重複する画像がマージされます。 幸いなことに、OSにはこの問題に対する解決策があります。 レイアウトは別のオフスクリーンバッファにコピーされ、アルファはこのバッファ全体に適用され、結果はフレームバッファにコピーされます。 結果:



画像



しかし...私たちはこれに代価を払います。



フレームバッファーで行われる前にオフスクリーンバッファーでビューを追加レンダリングすると、別の不可視のオーバードローレイヤーが追加されます。 OSは、以前にこのアプローチまたは直接的なアプローチをいつ使用するかを正確に知らないため、デフォルトでは常に1つの複雑なアプローチを使用します。 ただし、アルファを設定し、オフスクリーンバッファを追加する難しさを回避する方法はまだあります。



ハードウェアアクセラレーション



Honeycombにハードウェアアクセラレーションが含まれていたとき、画面にアプリケーションを表示する新しいレンダリングモデルを取得しました。 これには、画像取得を高速化するためのビューレンダリングコマンドを記述するDisplayList構造が含まれます。 しかし、開発者が通常忘れる別の興味深い機能があります-プレゼンテーションレベル。



これらを使用して、オフスクリーンバッファにビューを描画し(アルファチャネルを使用したときに見たように)、必要に応じて操作できます。 複雑なビューをより速くアニメーション化できるため、これはアニメーションに最適です。 レベルがないと、アニメーションプロパティ(x座標、スケール、アルファ値など)を変更した後、プレゼンテーションアニメーションにアクセスできなくなります。 複雑な表現の場合、この機能は子孫の表現にまで及ぶため、子孫は自分自身を再描画しますが、これは高価な操作です。 プレゼンテーションレベルを使用し、ハードウェアに依存して、プレゼンテーションのテクスチャをGPUで作成します。 x / y軸に沿った位置の変更、回転、アルファなど、テクスチャを置き換える必要なくテクスチャに適用できる操作がいくつかあります。 これは、アニメーション中にそれらを置き換えることなく、画面上の複雑なビューをアニメーション化できることを意味します! これにより、アニメーションがスムーズになります。 これを行う方法を示すサンプルコードを次に示します。



 // Using the Object animator view.setLayerType(View.LAYER_TYPE_HARDWARE, null); ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, 20f); objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { view.setLayerType(View.LAYER_TYPE_NONE, null); } }); objectAnimator.start(); // Using the Property animator view.animate().translationX(20f).withLayer().start();
      
      







ちょうどいい?



はい。ただし、ハードウェアレベルを使用する際に留意すべき点がいくつかあります。





2番目のケースでは、この更新を視覚化する方法があります。 開発者の設定を使用して、「ハードウェアレイヤーの更新を表示」を有効にできます。



画像



その後、ハードウェアレベルで更新すると、ビューが緑色で強調表示されます。 しばらく前に、期待したスムージングでページを反転させないViewPagerがあったときにこれを使用しました。 このオプションをオンにした後、私は戻ってViewPagerをめくってみました。これは私が見たものです:



画像



どちらのページもスクロール全体で緑色でした!



これは、ハードウェアレベルがページの最適化に使用され、ViewPagerをめくるとページが使用できなくなったことを意味します。 ページを更新し、バックグラウンドで視差効果を使用してページをめくると、ページ上の要素を徐々にアニメーション化しました。 私がしなかったことは、ViewPagerページのハードウェアレイヤーを作成しなかったことです。 ViewPagerコードを調べたところ、ユーザーがスクロールを開始すると、両方のページがハードウェアレベルで作成され、スクロールの終了後に削除されることがわかりました。



ハードウェアレベルを使用してページをスクロールすることは理にかなっていますが、私の場合、これは適合しませんでした。 通常、ViewPagerをスクロールしてもページは変更されません。また、ページは非常に複雑になる可能性があるため、ハードウェアレベルにより、レンダリングがはるかに高速になります。 私が取り組んでいたアプリケーションでは、そうではなかったので、 自分で書いた小さなハックを使用してこのハードウェア層を削除しました



ハードウェア層は特効薬ではありません。 それがどのように機能するかを理解し、適切に使用することが重要です。さもないと、大きな問題にぶつかる可能性があります。



自分でやる



ここに示すすべての例の準備として、これらの状況をシミュレートするために多くのコードを書きました。 これらは、GithubリポジトリGoogle Playで見つけることができます。 さまざまなアクティビティのスクリプトを分割し、アクティビティを使用しているときに発生する可能性のある問題の種類を理解できるように、できるだけスクリプトを文書化しようとしました。 アクティベーションドキュメントを読み、ツールを開いて、アプリケーションを操作します。



詳細情報



Android OSの進化に伴い、アプリケーションを最適化する方法があります。 Android SDKに新しいツールが導入され、OSに新しい機能が追加されました(ハードウェアレベルなど)。 何かを変えることを決める前に、新しいことを学び、妥協を学ぶことが非常に重要です。



Android Performance Patternsと呼ばれる素晴らしいYouTubeプレイリストがあります。パフォーマンスに関するさまざまなことを説明するGoogleの短いビデオがたくさんあります。 異なるデータ構造(HashMapとArrayMap)の比較、ビットマップの最適化、さらにはネットワーク要求の最適化についても見つけることができます。 それらすべてを見ることを強くお勧めします。



Android Performance Patterns Google+コミュニティに参加して、Googleの従業員を含む他のメンバーとパフォーマンスについて話し合い、アイデア、記事、質問を共有してください。



他の興味深いリンク





今日、アプリケーションの最適化を開始するのに十分な情報と自信があることを願っています!



トレースを開始するか、他の利用可能な開発者オプションのいくつかを有効にして、それらから始めます。 コメントであなたの考えを共有することをお勧めします。



All Articles