Android開発パフォーマンス最適化まとめ(1)

Android アプリの開発では、まず優れたユーザー エクスペリエンスに注意を払う必要があります。ソフトウェアが深刻にフリーズしたり、スムーズでなかったり、頻繁にクラッシュしたりすると、ユーザーに非常に悪いエクスペリエンスをもたらし、ユーザーを失うことになります。
実際の開発や学習において、参考や交換のために Android のパフォーマンスの最適化についてまとめました。

アプリのパフォーマンスの問題は、初回起動速度が遅い、特定のインターフェイスに入る速度が遅い、アニメーションの実行プロセスがスムーズでない、アニメーションの実行が長時間フリーズするなど、さまざまな側面に反映されます。 ; プログラムによってカスタマイズされた特定のインターフェイスの実行速度が遅い; 特定のユーザー イベントに応答する際に長時間応答がない (ANR); データベースを操作する際に、大規模なデータの追加、削除、変更、クエリが発生するデータ量が多く実行速度が遅い ファイルの読み書きが頻繁でキャッシュファイルが大きすぎる フリーズの原因; アプリケーションを長時間実行していると、ランダムにフリーズが発生します。

上記の問題の原因は複数ある可能性があり、アプリケーション自体に問題がない場合や、システムの他の層に問題があるにもかかわらずアプリケーション層にのみ反映されている場合もあります。したがって、開発者がパフォーマンスの問題に対処する場合、最初に行う必要があるのは、パフォーマンスの問題がアプリケーション自体によって引き起こされているかどうかを判断し、適切な薬を処方することですが、アプリケーション自体のロジックは正常であっても、アプリケーション自体が原因である場合があります。システムのハードウェア構成が不十分な場合、異常が発生するため、ハードウェア構成の不足を補うために、製品またはプロジェクトの要件に応じてパフォーマンスを最適化するためのより正確な方法を採用する必要があります。

以下に、いくつかの異なる角度からアプリケーションのパフォーマンスを最適化するいくつかの方法をまとめます。

1. プログラミングのアイデア

アプリケーション層でのパフォーマンスの最適化は、通常、次の側面から検討できます。

  1. プログラミング言語のコンパイル原理を理解し、効率的なコーディング方法を使用してプログラムのパフォーマンスを構文的に向上させます。
  2. 合理的なデータ構造とアルゴリズムを使用して、プログラムのパフォーマンスを向上させます。これがプログラムのパフォーマンスの鍵となることがよくあります。
  3. インターフェースのレイアウトの最適化に注意してください。
  4. マルチスレッド、データのキャッシュ、遅延ロード、早期ロードなどの手段を使用して、深刻なパフォーマンスのボトルネックを解決します。
  5. 仮想マシンのヒープ メモリの上限と使用率を合理的に構成して、ガベージ コレクションの頻度を減らします。
  6. ネイティブ コードの合理的な使用。
  7. データベース キャッシュ タイプを合理的に構成し、SQL ステートメントを最適化して読み取り速度を高速化し、トランザクションを使用して書き込み速度を高速化します。
  8. ツールを使用してパフォーマンスの問題を分析し、パフォーマンスのボトルネックを見つけます。
    もちろん、パフォーマンスを最適化する方法は他にもたくさんあるはずですが、ここでは一般的に使用される方法の一部のみを紹介します。

2. プログラミング スキルAndroid 公式 Web サイトには、アプリケーションのパフォーマンスを向上させるためのヒントがいくつかあります。ここでは、簡単なリストと実際の開発での私自身の経験をいくつか紹介します。詳細は、公式 Web サイトのドキュメント
から入手できますこの記事に記載されている最適化手法は主に若干のパフォーマンス向上であり、プログラムの全体的なパフォーマンスはプログラムのビジネス ロジック設計、コードのデータ構造、アルゴリズムに依存することに注意してください。研究開発担当者は、これらの最適化手法を通常のコーディング プロセスに適用する必要があり、これはパフォーマンスに大きな影響を与えます。効率的なコードを書くには、2 つの原則に従う必要があります:不必要な操作を実行しない、不必要なメモリを割り当てない、2 つの原則はそれぞれ CPU とメモリに向けられており、完了することを前提として CPU とメモリのリソースを可能な限り節約します。必要な操作が実行されるため、実行効率が高くなければなりません。単純に言うだけでは空虚に聞こえますが、結局何が必要で何が不必要なのかを判断する統一の基準はなく、具体的な状況と組み合わせて分析する必要があります。1. 不要なオブジェクトの作成を避けるオブジェクトの作成にはコストがかかります。一時オブジェクト用のスレッドレベルの割り当てプールを備えた世代別ガベージ コレクターは、割り当てコストを削減できますが、メモリを割り当てると、メモリを割り当てない場合よりも常にコストが高くなります。オブジェクトを作成しすぎると、パフォーマンスが低下します。第一に、メモリの割り当て自体に時間がかかります。第二に、仮想マシン実行時のヒープ メモリの使用量には上限があります。使用量が一定のレベルに達すると、ガベージ コレクションが実行されます。ガベージ コレクションによってスレッドが作成され、プロセス全体が一時停止されることもあります。オブジェクトの作成と破棄が頻繁に行われる場合、またはメモリ使用量が多い場合、アプリケーションが深刻なスタック状態になることが考えられます。2. static の合理的な使用オブジェクトのフィールドにアクセスする必要がない場合は、対応するメソッドを static にします。通話速度は約15%~20%向上します。理解すべき主なポイントは 3 つあります。メソッドが実行時に動的変数とメソッドを操作する必要がない場合、メソッドを静的に設定できます。











定数フィールドは、dex ファイルの静的フィールド初期化子に格納され、直接アクセスされるため、「static Final」として宣言する必要があります。それ以外の場合は、実行時のコンパイル時に自動的に生成されるいくつかの関数によって初期化する必要があります。このルールは、プリミティブ型と String 型に対してのみ有効です。
View オブジェクトは Activity オブジェクトを参照するため、ビュー コントロールを静的として宣言しないでください。Activity が終了すると、オブジェクト自体を破棄できず、メモリ オーバーフローが発生します。
3. 内部ゲッター/セッターを避ける
オブジェクト指向設計では、通常、フィールド アクセスにゲッター/セッターを使用するのが良い原則ですが、フィールドをパブリックにアクセスする必要がある場合を除き、Android 開発のハードウェア条件に限定されます。限られた範囲の内部アクセスのみ (パッケージ内でのアクセスなど) には、Getter/Setter の使用は推奨されません。JIT がオンの場合、直接アクセスは間接アクセスより 7 倍高速になります。
4. 拡張 for ループの使用
効率を高めるために、一般に拡張 for ループの使用を優先します。ArrayList を走査する場合などの 1 つのケースを除いて、通常の for ループを使用する方が効率的です。
5. プライベート内部クラスの場合は、プライベート アクセス権の代わりにパッケージ アクセス権を使用することを検討してください。
プライベート内部クラスのメソッドは、プライベート メンバー変数および外部クラスのメソッドにアクセスします。これは文法的には正しいですが、仮想マシンはそれらに直接アクセスしません。代わりに、いくつかのパッケージ レベルの静的メソッドがコンパイル時に外部クラスで自動的に生成され、内部クラスはこれらの静的メソッドを呼び出して、実行中に外部クラスのプライベート メンバーにアクセスします。この場合、メソッド呼び出しの追加レイヤーが存在し、パフォーマンスが失われます。
この問題を解決する 1 つの方法は、外部クラスのプライベート メンバーをパッケージ レベルに変更して、内部クラスに直接アクセスできるようにすることです。もちろん、設計が受け入れられることが前提です。
6. 浮動小数点型の使用を避ける
Android デバイスでは、浮動小数点型は整数データ処理の約 2 倍遅いため、整数で問題を解決できる場合は浮動小数点型を使用しないでください。
また、一部のプロセッサにはハードウェア乗算はありますが、除算はありません。その場合、除算とモジュロ演算はソフトウェアで実装されます。効率を向上させるために、計算式を記述するときに一部の除算演算を乗算として直接書き換えることを検討できます。たとえば、「x / 2」を「x * 0.5」に書き換えます。

7.<merge>最適化されたレイアウト層を採用します。<include>レイアウトを共有することを採用します。
8. ビューの読み込みを遅延します。頻繁に参照されないビューが長時間参照されてメモリを占有することを避けるために、ViewStub を使用します。 9.
アクティビティのデフォルトの背景を削除して、アクティビティの読み込み速度を向上させます。
アクティビティで不透明な背景を使用していることが確実な場合は、アクティビティのデフォルトの背景を削除できます。
コード内: getWindow().setBackgroundDrawable(null);
スタイル スタイル ファイルで設定し、マニフェスト ファイルで構成することもできます。

 <style name="MyStyle" parent="AppTheme">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowBackground">@null</item>  
 </style>

10. カーソルの使用
カーソルの開閉には非常に時間がかかるため、カーソルを適切に管理するように注意してください。カーソルを毎回開閉しないでください。
使用されなくなったカーソルは必ず閉じてください (通常は、finally ステートメント ブロックで実行されます)。
CursorAdapter の場合のように、カーソルを直接閉じることができない状況がありますが、CursorAdapter はアクティビティの終了時にカーソルを自動的に閉じないので、onDestroy 関数で手動でカーソルを閉じる必要があることに注意してください。

protected void onDestroy() { 
      if (mAdapter != null && mAdapter.getCurosr() != null) { 
	      mAdapter.getCursor().close(); 
      } 
      super.onDestroy(); 
	}

11. BroadCast の動的登録をブロードキャストする場合は、メモリ リークを防ぐために、呼び出し元のライフ サイクルの終了時に必ず Receiver を登録解除してください。
12. ListView 項目のパフォーマンスを最適化して
、使用されるコントロールとレイアウトのレベルをできる限り削減します。背景色は、cacheColorHint と同じ色に設定されます。ListView 内の項目のレイアウトは非常に重要であり、使用されるコントロールとレイアウトは可能な限り削減する必要があります。RelativeLayout は、レイアウトのレベルを下げることができる絶対的な武器です。同時に、コントロールを可能な限り再利用する必要があります。これにより、ListView のメモリ使用量が削減され、スライド時の GC の数が削減されます。ListView の背景色は、cacheColorHint と同じ色に設定されます。これにより、スライド時のレンダリング パフォーマンスが向上します。ListView の getView のパフォーマンスが重要であり、ここで可能な限り最適化する必要があります。ビューは getView メソッドで再利用する必要があります。複雑な論理計算、特にデータベース操作は getView メソッドでは実行できません。そうしないと、スライドのパフォーマンスに重大な影響を及ぼします。ListView に多くのデータ項目がある場合は、ページネーションの読み込みを検討してください。13.複数のスレッドが同時にオブジェクトにアクセスするときに例外が発生しないように、
スレッド同期メカニズム (synchronized) を使用することに注意してください。
14. StringBuffer、StringBuilder、および String の合理的な使用
単純な文字列の連結では、たとえば String s = "hello" + "world"; のように String が最も効率的ですが、
文字列が From another String である場合は、ここに注意してください。オブジェクトの場合、速度はそれほど速くありません。例:
    String str2 = "This is";
    String str3 = "a";
    String str4 = "test";
    String str1 = str2 + str3 + str4;
ここでは StringBuilder が必要です
シングルスレッドでは StringBuffer よりも StringBuilder の方がパフォーマンスが高くなります。マルチスレッドでは同期されているため、スレッド セーフのために StringBuffer を使用する必要があります。通常の状況では、StringBuilder が一般的に使用されます。
15. ローカル変数を使ってみる
メソッドの呼び出し時に渡されるパラメータと呼び出し中に作成される一時変数はすべてスタック (Stack) に保存されるため、処理が高速になります。静的変数、インスタンス変数などの他の変数はヒープ (Heap) に作成されますが、これは低速です。さらに、特定のコンパイラ/JVM によっては、ローカル変数がさらに最適化される場合があります。
16. I/O ストリーム操作に間に合うように、必ずストリーム オブジェクトを閉じてください。
17. Service の代わりに IntentService を使用します
。 IntentService と Service はどちらもサービスです。違いは、IntentService がキューを使用して要求されたインテントをキューに追加し、ワーカー スレッド (スレッド) を開始してキュー内のインテントを処理することです ( onHandleIntent メソッド)、非同期 startService リクエストの場合、IntentService は 1 つを処理し、次に 2 つ目を処理します。各リクエストは別個のワーカー スレッドで処理され、アプリケーションのメイン スレッドはブロックされません。新しいスレッドは、時間のかかる操作を処理するために IntentService を使用することもできます。
18. アクティビティ内のコンテキストの代わりにアプリケーション コンテキストを使用する ライフ サイクル
の長いオブジェクトがアクティビティ コンテキストを参照しないようにします。つまり、アクティビティを参照するオブジェクトがアクティビティ自体と同じライフ サイクルを持つようにします。
ライフサイクルが長いオブジェクトの場合は、
Context オブジェクトを静的に設定する代わりに、Application Context を使用できます。
19. コレクション内のオブジェクトは、適時にクリーンアップする必要があります。
 通常、いくつかのオブジェクト参照をコレクションに追加します。オブジェクトが必要ないときは、コレクションからその参照をクリーンアップしないため、コレクションは次のようになります。どんどん大きくなっていきます。コレクションが静的である場合、状況はさらに深刻になります。
20.
Bitmap の利用 大きな Bitmap は圧縮に注意して使用してください。高解像度の大きな画像を読み込む場合は、BitmapRegionDecoder の使用を検討してください。未使用のBitmap の  時間内にrecycle() に注意してください

21. ソフト参照を使用します (SoftRefrence) ) 上手に
Bitmap を使用した後は、その Bitmap への参照が保持されないため、Recycle 関数を呼び出すことができません。このとき、ソフト参照を賢く使用すると、メモリが不足しているときにビットマップを効果的に解放できます。Java 参照メカニズムの概要については、私の他のブログを参照してください: Java オブジェクトの 4 つの参照タイプ
22. 大きな画像全体をリソース ファイルとして使用せず、9path 画像を使用するようにしてください
。環境)、その他のリソース マップ、および .9 マップは、drawable-xxxx の下に配置する必要があり、携帯電話の SD カードにコピーする必要がある画像は、assets ディレクトリに配置する必要があります。png の代わりに webp 画像を使用すると、画像サイズを大幅に削減できます。
23. ライブラリ関数を理解して使用する
Java 標準ライブラリと Android フレームワークには、効率的で堅牢なライブラリ関数が多数含まれており、多くの関数はネイティブに実装されており、通常、同じ関数を Java で実装するコードよりもはるかに効率的です。したがって、システム ライブラリ関数を上手に使用すると、開発時間を節約でき、エラーが発生しにくくなります。
24. WebView に関しては、
Activity または Fragment が破棄されたときに WebView を忘れずに破棄してください

@Override
    protected void onDestroy() {
        if (webView!= null) {
            webView.destroy();
            webView= null;
        }
        super.onDestroy();
    }

25. JNI
と Android NDK を合理的に使用して、ネイティブ コードを使用してアプリケーションを開発することは、必ずしも Java 言語でプログラミングするよりも効率的であるとは限りません。まず、Java ネイティブへの移行にはコストがかかり、JIT はこれらの境界を超えて最適化することができません。ネイティブ リソース (ネイティブ ヒープ上のメモリ、ファイル記述子、またはその他の要素) を割り当てている場合、これらのリソースを適時に再利用できるように手配することがはるかに困難になる可能性があります。また、コードを実行するアーキテクチャごとにコードをコンパイルする必要があります。異なる CPU アーキテクチャに合わせて、複数のバージョンの so ライブラリをコンパイルする必要がある場合もあります。
ネイティブ コードは主に、Java 言語で記述された Android アプリの一部を「高速化」するためではなく、既存のネイティブ コード ベースを Android に移植する場合を目的としています。
26. 例外キャプチャ メカニズムを有効に活用します。Java
には、コード例外をキャッチするための try-catch 構文ブロックが用意されています。日常の開発では、多くの状況を十分に考慮することはできず、例外はいつでも発生する可能性があります。堅牢なコードには例外処理が含まれている必要があります。このメカニズムでは、try-catch を合理的に使用すると、多くのアプリケーションがクラッシュするという問題を回避でき、開発者が問題を迅速に特定するのにも役立ちます。
27. 消費電力の最適化
アプリの消費電力は主に以下に反映されます。
1. 頻繁なオブジェクトの作成、時間のかかる操作、または複雑な計算操作
2. アプリが積極的に画面を起動するか、画面が常にオンになるように制御します。画面の明るさを積極的に上げる
3. バックグラウンドのタイミング 長時間にわたるタスクやサービスの実行
開発者は、これらの 3 つのポイントに基づいて、これらの動作を最適化して電力を節約する方法を検討できます。

3. ツールを使用してアプリケーションのパフォーマンスを分析します
(この部分にはさらに多くの内容が含まれています。詳細については、「Android 開発パフォーマンスの最適化の概要 (2)」を参照してください。

おすすめ

転載: blog.csdn.net/gs12software/article/details/51173392