記事ディレクトリ
第8章パフォーマンスの最適化アプリの起動の最適化(2)
(1)スタート画面白画面/黒画面解像度
1.現象
アプリを開くと、多くの場合、起動ページに入る前にしばらく一時停止します(スプラッシュ)
2.理由
Acitivtyを開始するonCreate()メソッドでは、システムは最初にフォームを描画してから、setContentView(R.layout.activity_splash)を実行します。フォームが描画された後、レイアウトリソースはロードされていないため、デフォルトの背景色が使用されます。
テーマがTheme.AppCompat.Light(明るい色システム)を使用している場合、白いスプラッシュスクリーンを表示し、ThemeOverlay.AppCompat.Dark(暗い色システム)を使用している場合、黒いスプラッシュスクリーンを表示します。
3.解決する
ステップ1:起動画像bg_splashをフォームの背景として設定し、アプリが起動したときの外観を回避します。黒/白の画面
ステップ2:背景bg_splashディスプレイとして設定すると、背景はリソースのロードと広告画像のダウンロード、広告画像のダウンロードを担当します成功時またはタイムアウト時にSplashActivityの実際の外観を表示する
ステップ3:次にMainAcitivityを入力します
<style name="ThemeSplash" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:background">@mipmap/bg_splash</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
(2)起動速度の最適化
1. Androidアプリケーションの起動プロセス分析
(1)アプリの基本理論
各Androidアプリは別のスペースにあります。つまり、別のプロセスで実行され、独自のVMがあり、システムによって一意のユーザーIDが割り当てられます
。Androidアプリは、他のコンポーネントも起動できるさまざまなコンポーネントで構成されていますアプリコンポーネント。したがって、Androidアプリには、プログラムエントリに似たmain()メソッドがありません
。AndroidプロセスはLinuxプロセスと同じです。デフォルトでは、各apkは独自のLinuxプロセスで実行されます。さらに、デフォルトプロセスには1つしかありません。スレッド-メインスレッド。このメインスレッドにはLooperインスタンスがあり、対応する処理のためにLooper.loop()を呼び出すことによりメッセージキューからメッセージが取得されます。
プロセスは必要なときに開始されます。ユーザーまたは他のコンポーネントがいつでもapkのいずれかのコンポーネントを呼び出すと、apkが実行されていない場合、システムはそのための新しいプロセスを作成して起動します。通常、このプロセスは、システムによって強制終了されるまで実行され続けます。
(2)アプリの起動プロセス
ユーザーがホームのアプリアイコンをクリックしてアプリケーションを開始すると、
クリックイベントはstartActivity(インテント)を呼び出し、LauncerはバインダーIPCメカニズムを使用し、最後にActivityManagerServiceに通知します(AMSはAndroidシステムのプロセスであり、システムの4つの主要コンポーネントの操作を管理するために使用されますステータス)アクティビティを開始します。
サービスは次の操作を実行します。
最初のステップ:PackageManagerのresolveIntent()を介してこのインテントオブジェクトのポインティング情報を収集します。ポインティング情報はインテントオブジェクトに格納されます
。2番目のステップ:grantUriPermissionLocked()によってユーザーが十分かどうかを確認しますインテントオブジェクトが指すアクティビティを呼び出すための権限。
権限がある場合、ActivityManagerServiceは新しいタスクでターゲットアクティビティを確認して開始します。
ステップ3:このプロセスのProcessRecordが存在するかどうかを確認します。存在する場合、ProcessRecordがnullの場合はアクティビティを直接開始します。 、ActivityManagerServiceは、ターゲットアクティビティをインスタンス化する新しいプロセスを作成します
。ステップ4:ActivityManagerServiceは、startProcessLocked()メソッドを呼び出して新しいプロセスを作成します。このメソッドは、上記のソケットチャネルを介してZygoteプロセスにパラメーターを渡します。Zygoteは自身をインキュベートして呼び出しますZygoteInit.main()メソッドでActivityThreadオブジェクトをインスタンス化し、最後に新しいプロセス
ActivityThreadのpidを返し、次にLooper.prepareLoop()とLooper.loop()を呼び出してメッセージループを開始します。
ステップ5:プロセスを指定されたアプリケーションにバインドする
ステップ6:既存のプロセスでrealStartActivity()を呼び出してアクティビティを開始する
2.アプリの起動方法
(1)コールドスタート
アプリが起動していないか、アプリプロセスが強制終了されています。アプリプロセスはシステムに存在しません。現時点
では、アプリの起動はコールドスタートです。コールドスタートプロセスは、セクション2で説明するアプリ起動プロセスのプロセス全体です。アプリプロセスを作成する必要があります、関連リソースのロード、メインスレッドの開始、最初の画面のアクティビティの初期化など。
このプロセス中、最初の画面のアクティビティが完全に開始されるまで、画面には空白のウィンドウ(色はテーマに基づく)が表示されます。
コールドスタートのタイムライン:
(2)ホットスタート
ホットスタートとは、アプリプロセスがバックグラウンドでのみ実行されることを意味します。システムは、バックグラウンドからフォアグラウンドにそれを取得してユーザーに表示します。
コールドスタートと同様に、このプロセス中、画面には空白のウィンドウ(テーマに基づく色)が表示されます。アクティビティがレンダリングされるまで。
(3)ウォームスタート
コールドスタートとホットスタートの間は、通常、次の2つの状況で発生し
ます。a。ユーザーがアプリを終了してから再起動します。アプリプロセスはまだ実行されている可能性がありますが、アクティビティを再構築する必要があります
。B。ユーザーがアプリを終了します。その後、システムはメモリのためにアプリを強制終了する可能性があり、プロセスとアクティビティの両方を再起動する必要がありますが、保存されたインスタンスの状態はonCreateで復元できます。
3つの起動状態の説明から、これから行う起動の最適化は実際にはコールドスタートアップ用であることがわかります。ホットスタートアップとウォームスタートアップはどちらも比較的高速です。
3.アプリの起動が遅い理由
コールドスタートタイムチャートによると、アプリの場合、開始タイムラインポイントを制御できるだけであることがわかります:
(3.1)アプリケーションonCreate
(3.2)最初の画面アクティビティのレンダリング
と現在のアプリが統合されています多くのサードパーティサービスは、起動時に広告や登録ステータスなどを確認する必要があります。一連のインターフェースは、アプリケーションのonCreateまたは最初の画面のonCreateで実行されます。
4.ケース分析
(1)コード分析
このアプリはBugly、Push、Feedbackなどのサービスを統合しているため、Application onCreateにはサードパーティのプラットフォーム用の多くの初期化作業があります。
public class GithubApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
// init logger.
AppLog.init();
// init crash helper
CrashHelper.init(this);
// init Push
PushPlatform.init(this);
// init Feedback
FeedbackPlatform.init(this);
// init Share
SharePlatform.init(this);
// init Drawer image loader
DrawerImageLoader.init(new AbstractDrawerImageLoader() {
@Override
public void set(ImageView imageView, Uri uri, Drawable placeholder) {
ImageLoader.loadWithCircle(GithubApplication.this, uri, imageView);
}
});
}
}
(2)TraceViewを使用してアプリケーションのonCreateを分析すると時間がかかる
次に、上記の理論的知識と導入されたTraceviewツールを組み合わせて、時間のかかるアプリケーションのonCreateを分析し、onCreate
の最初と最後にトレースをマークします。
Debug.startMethodTracing("GithubApp");
...
Debug.stopMethodTracing();
プログラムを実行すると、SDカードに「GithubApp.trace」ファイルが生成されます。
注:ストレージをプログラムに書き込むための許可を追加する必要があります。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
adb pullを介してローカルにエクスポートします
adb pull /sdcard/GithubApp.trace ~/temp
DDMS分析トレースファイルを開きます。トレースファイルを
分析します
。下のメソッド領域で[リアルタイム/呼び出し]をクリックし、メソッド呼び出しに従って降順で時間を並べ替えます。
注意を払うのに500ミリ秒以上かかります。
左側のメソッド名を見ると、時間のかかるビッグユーザーは、私たちが使用するいくつかの主要なプラットフォーム、特にBuglyの初期化メソッドです。また、ネイティブlibをロードし、ZipFileなどで動作します。
各メソッドをクリックすると、その親メソッド(それを呼び出す)とそのすべての子メソッドが表示されます(呼び出されます)
メソッドをクリックすると、上記のメソッドの実行時間軸が点滅し、実行スレッドとメソッドの相対期間が表示されます。
(3)アプリケーションのOnCreate最適化
サードパーティのSDK初期化を別のスレッドに配置します。ここで、A InitializeService IntentService DO初期化に使用される(サービスとは異なりIntentService、それがバックグラウンドスレッドである。)。
InitializeService.javaコードは次のとおりです。
public class InitializeService extends IntentService {
private static final String ACTION_INIT_WHEN_APP_CREATE = "com.anly.githubapp.service.action.INIT";
public InitializeService() {
super("InitializeService");
}
public static void start(Context context) {
Intent intent = new Intent(context, InitializeService.class);
intent.setAction(ACTION_INIT_WHEN_APP_CREATE);
context.startService(intent);
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_INIT_WHEN_APP_CREATE.equals(action)) {
performInit();
}
}
}
private void performInit() {
AppLog.d("performInit begin:" + System.currentTimeMillis());
// init Drawer image loader
DrawerImageLoader.init(new AbstractDrawerImageLoader() {
@Override
public void set(ImageView imageView, Uri uri, Drawable placeholder) {
ImageLoader.loadWithCircle(getApplicationContext(), uri, imageView);
}
});
// init crash helper
CrashHelper.init(this.getApplicationContext());
// init Push
PushPlatform.init(this.getApplicationContext());
// init Feedback
FeedbackPlatform.init(this.getApplication());
// init Share
SharePlatform.init(this.getApplicationContext());
AppLog.d("performInit end:" + System.currentTimeMillis());
}
}
GithubApplicationのonCreateを次のように変更します。
public class GithubApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
// init logger.
AppLog.init();
InitializeService.start(this);
}
}
(4)起動インターフェースの最適化
ステップ1:背景付きのテーマを作成する
<style name="SplashTheme" parent="AppTheme">
<item name="android:windowBackground">@drawable/logo_splash</item>
</style>
手順2:レイアウトをレンダリングしないアクティビティを起動画面として使用し、テーマを追加する
public class LogoSplashActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 注意, 这里并没有setContentView, 单纯只是用来跳转到相应的Activity.
// 目的是减少首屏渲染
if (AppPref.isFirstRunning(this)) {
IntroduceActivity.launch(this);
}
else {
MainActivity.launch(this);
}
finish();
}
}
<activity
android:name=".ui.module.main.LogoSplashActivity"
android:screenOrientation="portrait"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
5.まとめ
(1)Application onCreateであまり多くのことを行わない
(2)最初の画面のアクティビティはできるだけ簡略化する必要がある
(3)分析にはパフォーマンス分析ツールを活用する。