Android パフォーマンス最適化 - APP 起動最適化の詳細な説明

1.1 最適化を始める理由

ユーザーはアプリの応答性と読み込みが速いことを期待していますが、起動に時間がかかりすぎるアプリはこの期待に応えられず、ユーザーをイライラさせる可能性があります。

開始が遅すぎる場合の結果:

  • 悪い経験
  • ユーザーがアプリを放棄する
  • 時間が長いほど、ユーザー チャーンが高くなります。
  • 製品ダイ

1.2 最適化プロセスと分類の開始

1.2.1 起動プロセス

1.2.2 分類開始

  • コールド スタート: アプリが最初から開始されます (デバイスの起動後、またはシステムがアプリを終了した後に初めてアプリを開始するとき)。
  • ホット スタート:Activityフォアグラウンドに移動します (すべてのアプリケーションがActivityまだメモリに常駐している場合、アプリケーションはオブジェクトの初期化、レイアウトの展開、およびレンダリングを繰り返す必要はありません。呼び出しメソッドなどのシステムではonTrimMemory、これらのオブジェクトはウォーム スタート イベントに応答して再作成する必要があります)。
  • ウォーム スタート: コールド スタート中に発生する操作のサブセットをカバーしますが、同時にウォーム スタートよりも多くのオーバーヘッドが発生します (ウォーム スタートとの最大の違いは、メソッドを呼び出してアクティビティを再作成する必要があることです。または、保存されたインスタンスの状態から何らかのオブジェクト リカバリにonCreate渡されたメソッドから)。onCreate

コールド スタート プロセス:

  1. ロードして開始しますAPP
  2. 起動直後にAPP空白の起動ウィンドウを表示します。
  3. プロセスの作成APP(アプリケーション オブジェクトの作成);
  4. メイン スレッドを開始し、メイン スレッドを作成しますActivity
  5. レイアウトを読み込み、描画します。

起動概要:

Appシステムによって呼び出されてから最初のページを携帯電話の画面にレンダリングするまで、通常は 、最初の 、 、および メソッドに注意を払うだけApplication済みますonCreateActivityonCreateonStartonResume

注: 最初のメソッドに独自のロジックがあるだけでなく、メソッド内の他のページに直接ジャンプする場合はAppジャンプ3メソッドも最適化する必要があります。ActivityActivityonCreateonStartonResumeActivityActivity

1.2.3 白黒画面の最適化

システムがロードされて起動するまでにはApp、それに相当する時間がかかります.1秒未満の時間でも、ユーザーはAppアイコンをクリックするときに「遅延」があると感じます.この問題を解決するためにGoogle、最良の方法は、作成プロセス中ですApp. 最初に空白のページを表示して、ユーザーがアイコンをクリックした直後に応答を体験できるようにします. この空白のページの色は、ファイルで構成したテーマの色に従って決定されますManifest.デフォルトは白です。

システムテーマを採用する代わりに、アプリケーションの起動画面がアプリケーションのその後の効果とテーマが一致するように、アプリケーションのロード用のテーマを設定することが可能です。

解決策 1 : 設定LauncherTheme

LauncherTheme、システムの「プレビューのキャンセル (空白のフォーム)」を に設定するtrueか、空白のフォームを透明に設定して、ユーザーが白黒画面の存在を視覚的に確認できないようにします。

<style name="AppTheme.LauncherTheme">
	<!--设置系统的取消预览(空白窗口)为true-->
  <item name="android:windowDisablePreview">true</item>
  <!--设置背景为透明-->
  <item name="android:windowIsTranslucent">true</item>
</style>

解決策 2 :Themeテーマをカスタマイズする

  1. AppTheme継承元のテーマをカスタマイズします。
  2. スタートアップをカスタム テーマActivityとして設定します。Theme
  3. startActivityメソッドでonCreatesuper.onCreateandメソッドsetContentViewの前にメソッドを呼び出してsetTheme、テーマを initial に設定しますAppTheme

①カスタムテーマ

<style name="AppTheme.LaunchTheme1">
	<item name="android:windowBackground">@mipmap/ic_launcher</item>
</style>

②起動Activityテーマを設定する

<activity android:name=".MainActivity"
          android:theme="@style/AppTheme.LaunchTheme1">
	<intent-filter>
  	<action android:name="android.intent.action.MAIN"/>
    <category android:name="android.intent.category.LAUNCHER"/>
  </intent-filter>
</activity>

③テーマをコードに戻す

protected void onCreate(Bundle savedInstanceState) {
    
    
  	setTheme(R.style.AppTheme)
    super.onCreate(savedInstanceState);
}

1.3 起動時間の測定

1.3.1 測定方法

  • Syslog 出力: onAndroid4.4以上には、コマンド is の値をlogcat含む出力行が含まれます。これは、プロセスの開始から画面へのアプリの描画を終了するまでの経過時間を表します (テスト済み、ありませんでした)。DisplayedActivityMI6

    1. プロセスを開始します。
    2. オブジェクトを初期化します。
    3. 作成および初期化Activity: ActivityManager:displayed com.sty.ne.appperformance/.MainActivity: +550ms;
    4. レイアウトを展開します。
    5. 初塗装。
  • adbコマンド: adb shell Activity Manager:

adb [ -d | -e | -s <serialNumber>] shell am start -S -W
com.sty.ne.appperformance/.MainActivity
-c android.intent.category.LAUNCHER
-a android.intent.action.MAIN

adb shell am start -W com.sty.ne.appperformance/.MainActivity
显示结果如下:
GGGdeMac-mini:NeAppPerformance tian$ adb shell am start -W com.sty.ne.appperformance/.activity.SplashActivity
Starting: Intent {
    
     act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.sty.ne.appperformance/.activity.SplashActivity }
Status: ok
Activity: com.sty.ne.appperformance/.MainActivity
ThisTime: 186  (最后一个Activity启动耗时)
TotalTime: 395  (所有Activity启动耗时)
WaitTime: 417  (AMS启动Activity的总耗时)
Complete
  • 手動取得: ログを手動で印刷して起動時間を計算し、アプリケーションで費やされた時間のみを記録します。
private void findViews() {
  final View viewRoot = findViewById(R.id.root);
  viewRoot.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
    @Override
    public boolean onPreDraw() {
      viewRoot.getViewTreeObserver().removeOnPreDrawListener(this);
      LauncherTimer.logEnd("tag3");
      return false;
    }
  });
}

@Override
protected void onResume() {
  super.onResume();
  LauncherTimer.logEnd("tag1");
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
  super.onWindowFocusChanged(hasFocus);
  LauncherTimer.logEnd("tag2");
}
// D/Time: 2/tag1 launcher time=101
// D/Time: 2/tag3 launcher time=139
// D/Time: 2/tag2 launcher time=146

1.3.2 メソッドの時間のかかる統計

  • traceview統計Android Studio: コード統計を使用するか、組み込みのcup profiler統計を使用できますが、欠点は、コードが非常に煩雑で、プログラムの実行が遅くなることです。

    Debug Trace

    @Override
    public void onCreate() {
          
          
      super.onCreate();
      Debug.startMethodTracing("Launcher");
    
      coreSize = Runtime.getRuntime().availableProcessors();
      executorService = Executors.newFixedThreadPool(Math.max(2, Math.min(coreSize - 1, 4)));
      application = this;
      context = this.getApplicationContext();
      AppProfile.context = context;
      ScreenUtil.init(context);
      initLog();
      AppForegroundWatcher.init(context);
      CrashReport.initCrashReport(getApplicationContext(), "e9bf59bd43", false);
    
      Debug.stopMethodTracing();
      //sdcard/Android/data/com.sty.ne.appperformance/files/Launcher.trace  --> save as 导出来,用Profiler打开
    }
    

    sdcard/Android/data/com.sty.ne.appperformance/files/Launcher.trace-->下の図に示すように、save asエクスポートして で開きます。Profiler

短所:アプリ内プログラムの実行時間しか記録できません。

CPU Profiler:

煩わしいコードは必要ありません ( を記述する必要はありませんDebug.startMethodTracing("Launcher") が、次の構成が必要です。

  1. run-> edit configurations
  2. ダニstart recording a method trace on startup;
  3. メニューから [レコード設定] を選択しますcpu(profilingメニューの下にある 2 つのチェックボックスにチェックを入れます)。
  4. apply-->profileパターン展開。
  • systrace統計

    コマンドをコードに追加します。

    @Override
    public void onCreate() {
          
          
      super.onCreate();
      //systemtrace方式
      Trace.beginSection("Launcher");
    
      coreSize = Runtime.getRuntime().availableProcessors();
      executorService = Executors.newFixedThreadPool(Math.max(2, Math.min(coreSize - 1, 4)));
      application = this;
      context = this.getApplicationContext();
      AppProfile.context = context;
      ScreenUtil.init(context);
      initLog();
      AppForegroundWatcher.init(context);
      CrashReport.initCrashReport(getApplicationContext(), "e9bf59bd43", false);
    
      Trace.endSection();
    }
    

コマンド ライン ターミナルは、次のディレクトリに入ります。/Users/tian/Library/Android/sdk/platform-tools/systrace

次のコマンドを入力して、監視状態に入ります。

    python systrace.py -o mynewtrace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res

この時点でコードを実行し、完了後にコマンド ライン ウィンドウでEnterキーを押して、ターゲット ファイルが生成されますmynewtrace.html

ターゲット ファイルを分析します。

  • aopウェイ統計

1.4 最適化方法

1.4.1 非同期最適化

非同期最適化では、主にスレッドの初期化と並列実行にサブスレッドを使用して実行時間を短縮します。

@Override
public void onCreate() {
    
    
  super.onCreate();

  coreSize = Runtime.getRuntime().availableProcessors();
  executorService = Executors.newFixedThreadPool(Math.max(2, Math.min(coreSize - 1, 4)));
  application = this;
  context = this.getApplicationContext();
  AppProfile.context = context;
  ScreenUtil.init(context);
  async(new Runnable() {
    
    
    @Override
    public void run() {
    
    
      initLog();
    }
  });
  async(new Runnable() {
    
    
    @Override
    public void run() {
    
    
      AppForegroundWatcher.init(context);
    }
  });
  async(new Runnable() {
    
    
    @Override
    public void run() {
    
    
      CrashReport.initCrashReport(getApplicationContext(), "e9bf59bd43", false);
    }
  });
}

非同期最適化の注意点:

  1. 非同期で最適化できるかどうかを判断します。
  2. 一連の実行方法があるかどうか。
  3. 非同期後にプログラムが正常に実行できるかどうかに注意する必要があります。
  4. 非同期スレッドで使用するためにapi作成することはできませんHandler
  5. 操作できませんUI

1.4.2 遅延初期化

グローバル静的オブジェクトを作成する代わりに、すぐに必要なオブジェクトのみを初期化して、アプリケーションが最初にアクセスされたときにのみオブジェクトを初期化するシングルトン パターンに移行します。

1.4.3 アイドル時の初期化

アプリケーションのアイドル時間を監視し、アイドル時間中にアプリケーションを初期化できます。

public class DelayInit {
    
    
    private Queue<Runnable> delayQueue = new LinkedList<>();

    public void add(Runnable runnable) {
    
    
        delayQueue.add(runnable);
    }

    public void start() {
    
    
        Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
    
    
            @Override
            public boolean queueIdle() {
    
    
                Runnable poll = delayQueue.poll();
                if(poll != null) {
    
    
                    poll.run();
                }
                return !delayQueue.isEmpty();
            }
        });
    }
}

実はAndroidのパフォーマンス最適化には、起動最適化以外にもメモリ最適化、ネットワーク最適化、フリーズ最適化、ストレージ最適化などがありますので、マニュアルをクリックすると以下が参照できます。

「アプリ パフォーマンス チューニング アドバンスド マニュアル」:https://qr18.cn/FVlo89

スタートアップの最適化

メモリの最適化

UI の

最適化 ネットワークの最適化

ビットマップの最適化と画像圧縮の最適化

マルチスレッド同時実行の最適化とデータ転送効率の最適化

ボリューム パッケージの最適化

「Android パフォーマンス チューニング コア ノートのまとめ」:https://qr18.cn/FVlo89

「Android パフォーマンス監視フレームワーク」:https://qr18.cn/FVlo89

おすすめ

転載: blog.csdn.net/maniuT/article/details/130155774