1.1 最適化を始める理由
ユーザーはアプリの応答性と読み込みが速いことを期待していますが、起動に時間がかかりすぎるアプリはこの期待に応えられず、ユーザーをイライラさせる可能性があります。
開始が遅すぎる場合の結果:
- 悪い経験
- ユーザーがアプリを放棄する
- 時間が長いほど、ユーザー チャーンが高くなります。
- 製品ダイ
1.2 最適化プロセスと分類の開始
1.2.1 起動プロセス
1.2.2 分類開始
- コールド スタート: アプリが最初から開始されます (デバイスの起動後、またはシステムがアプリを終了した後に初めてアプリを開始するとき)。
- ホット スタート:
Activity
フォアグラウンドに移動します (すべてのアプリケーションがActivity
まだメモリに常駐している場合、アプリケーションはオブジェクトの初期化、レイアウトの展開、およびレンダリングを繰り返す必要はありません。呼び出しメソッドなどのシステムではonTrimMemory
、これらのオブジェクトはウォーム スタート イベントに応答して再作成する必要があります)。 - ウォーム スタート: コールド スタート中に発生する操作のサブセットをカバーしますが、同時にウォーム スタートよりも多くのオーバーヘッドが発生します (ウォーム スタートとの最大の違いは、メソッドを呼び出してアクティビティを再作成する必要があることです。または、保存されたインスタンスの状態から何らかのオブジェクト リカバリに
onCreate
渡されたメソッドから)。onCreate
コールド スタート プロセス:
- ロードして開始します
APP
。- 起動直後に
APP
空白の起動ウィンドウを表示します。- プロセスの作成
APP
(アプリケーション オブジェクトの作成);- メイン スレッドを開始し、メイン スレッドを作成します
Activity
。- レイアウトを読み込み、描画します。
起動概要:
App
システムによって呼び出されてから最初のページを携帯電話の画面にレンダリングするまで、通常は 、最初の 、 、および メソッドに注意を払うだけApplication
で済みます。onCreate
Activity
onCreate
onStart
onResume
注: 最初のメソッドに独自のロジックがあるだけでなく、メソッド内の他のページに直接ジャンプする場合は、App
ジャンプ後の3つのメソッドも最適化する必要があります。Activity
Activity
onCreate
onStart
onResume
Activity
Activity
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
テーマをカスタマイズする
AppTheme
継承元のテーマをカスタマイズします。- スタートアップをカスタム テーマ
Activity
として設定します。Theme
- start
Activity
メソッドでonCreate
、super.onCreate
andメソッド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 出力: on
Android4.4
以上には、コマンド is の値をlogcat
含む出力行が含まれます。これは、プロセスの開始から画面へのアプリの描画を終了するまでの経過時間を表します (テスト済み、ありませんでした)。Displayed
Activity
MI6
- プロセスを開始します。
- オブジェクトを初期化します。
- 作成および初期化
Activity
:ActivityManager:displayed com.sty.ne.appperformance/.MainActivity: +550ms
; - レイアウトを展開します。
- 初塗装。
-
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"
) が、次の構成が必要です。
run
->edit configurations
;- ダニ
start recording a method trace on startup
;- メニューから [レコード設定] を選択します
cpu
(profiling
メニューの下にある 2 つのチェックボックスにチェックを入れます)。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);
}
});
}
非同期最適化の注意点:
- 非同期で最適化できるかどうかを判断します。
- 一連の実行方法があるかどうか。
- 非同期後にプログラムが正常に実行できるかどうかに注意する必要があります。
- 非同期スレッドで使用するために
api
作成することはできませんHandler
。- 操作できません
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 の
最適化 ネットワークの最適化
ビットマップの最適化と画像圧縮の最適化
マルチスレッド同時実行の最適化とデータ転送効率の最適化
ボリューム パッケージの最適化