Androidアプリケーションの最初のフレームをレンダリングする

画像



みなさん、こんにちは!この投稿は、Androidアプリケーションをダウンロードして起動するプロセスの詳細について投稿の続きです。今日はもう少し進んで、アプリケーションのメインアクティビティが起動され、システムが最初のフレームをレンダリングする瞬間について説明します。猫の下でお願いします。



公式ドキュメント に従って、実行中のアプリケーションプロセスは、次の手順を実行する責任があります。



  1. Applicationクラスのオブジェクトを作成します。
  2. メインスレッド(MainThread、別名UiThread)を開始します。
  3. マニフェストで指定されている開始アクティビティの作成。
  4. ビューの拡張(膨張、膨張)。つまり、xmlファイルに登録されるビューの作成です。
  5. 画面上のビューのサイズ(View.measure())と配置(View.layout())のレイアウト。
  6. 初期レンダリングを実行します。


最初のフレームが描画された後、システムプロセスは表示された背景ウィンドウを置き換え、アプリケーションアクティビティに置き換えますこれで、ユーザーはアプリケーションを操作できます。



画像



それでは、すべてのステップを詳しく見ていきましょう。



メインストリームの開始



前回の投稿では、次のことを学びました。



  • アプリケーションプロセスが開始すると、ActivityThreadメソッドが呼び出されます。main()。これは、ActivityManagerServiceメソッドに対してブロッキングIPC要求を行います。system_serverプロセスのattachApplication()
  • system_server IPC- ActivityThread.bindApplication(), BIND_APPLICATION MessageQueue .
  • IPC- ActivityManagerService.attachApplication() , ActivityThread.main() Looper.loop(), ( ) MessageQueue.
  • , BIND_APPLICATION. ActivityThread.handleBindApplication(), APK .


画像



重要なポイント: ActivityManagerServiceメソッドへのIPC呼び出しが行われるまで、アプリケーションプロセスのメインスレッドでは何も起こりません。attachApplication()



アクティビティの開始を計画する



ActivityThreadメソッドを呼び出した後、system_serverプロセスで何が起こるかを見てみましょう。bindApplication()



public class ActivityManagerService extends IActivityManager.Stub {

  private boolean attachApplicationLocked(
      IApplicationThread thread, int pid, int callingUid,
      long startSeq) {
    thread.bindApplication(...);

    // See if the top visible activity is waiting to run
    //  in this process...
    mAtmInternal.attachApplication(...);

    // Find any services that should be running in this process...
    mServices.attachApplicationLocked(app, processName);

    // Check if a next-broadcast receiver is in this process...
    if (isPendingBroadcastProcessLocked(pid)) {
        sendPendingBroadcastsLocked(app);
    }
    return true;
  }
}


アクティビティの起動に関連する文字列はmAtmInternalです。attachApplication(...)このメソッドはActivityTaskManagerServiceを呼び出します。attachApplication()は、RootActivityContainerを呼び出します。attachApplication()



class RootActivityContainer extends ConfigurationContainer {

  boolean attachApplication(WindowProcessController app) {
    for (ActivityDisplay display : mActivityDisplays) {
      ActivityStack stack = display.getFocusedStack()
      ActivityRecord top = stack.topRunningActivityLocked();
      stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
      for (ActivityRecord activity : mTmpActivityList) {
        if (activity.app == null
            && app.mUid == activity.info.applicationInfo.uid
            && app.mName.equals(activity.processName)) {
          mStackSupervisor.realStartActivityLocked(
            activity,
            app,
            top == activity /* andResume */,
            true /* checkConfig */
          )
        }
      }
    }
    ...
  }
}


コードは次のことを行います。



  • すべての表示をバイパスします。
  • この表示のフォーカスされたアクティビティのスタックを取得します。
  • ターゲットアクティビティスタックの各アクティビティをループします。
  • アクティビティが実行中のプロセスに属している場合、ActivityStackSupervisorメソッドが呼び出されます。realStartActivityLocked()アクティビティがスタックの最上位にある場合andResumeパラメータはtrueになることに注意してください


これは、ActivityStackSupervisorメソッドがどのように見えるかです。realStartActivityLocked()



public class ActivityStackSupervisor{

  boolean realStartActivityLocked(
    ActivityRecord r,
    WindowProcessController proc,
    boolean andResume,
    boolean checkConfig
  ) {
    ...
    ClientTransaction clientTransaction = ClientTransaction.obtain(
            proc.getThread(), r.appToken);

    clientTransaction.addCallback(LaunchActivityItem.obtain(...));

    // Set desired final state.
    final ActivityLifecycleItem lifecycleItem;
    if (andResume) {
        boolean forward = dc.isNextTransitionForward()
        lifecycleItem = ResumeActivityItem.obtain(forward);
    } else {
        lifecycleItem = PauseActivityItem.obtain();
    }
    clientTransaction.setLifecycleStateRequest(lifecycleItem);

    // Schedule transaction.
    mService.getLifecycleManager()
      .scheduleTransaction(clientTransaction);
    ...
  }
}


これまでに確認したすべてのメソッド呼び出しは、system_serverプロセスで発生しますClientLifecycleManagerメソッド。scheduleTransaction()は、ActivityThreadに対してIPC呼び出しを行います。ClientTransactionHandlerを呼び出すアプリケーションプロセスのscheduleTransaction()executeTransaction ()を使用して、EXECUTE_TRANSACTIONメッセージをキューに入れます



public abstract class ClientTransactionHandler {

    /** Prepare and schedule transaction for execution. */
    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(
          ActivityThread.H.EXECUTE_TRANSACTION,
          transaction
        );
    }
}


EXECUTE_TRANSACTION メッセージを処理するときに、TransactionExecutorメソッドが呼び出されます。実行()



これで、図を更新できます。



画像



アクティビティの実際の開始



メソッドTransactionExecutor。execute()はTransactionExecutorを呼び出します。

performLifecycleSequence()は、ActivityThreadでコールバックを作成して、アクティビティを作成(作成)、開始(開始)、再開(再開)します。



public class TransactionExecutor {

  private void performLifecycleSequence(...) {
    for (int i = 0, state; i < path.size(); i++) {
      state = path.get(i);
      switch (state) {
        case ON_CREATE:
          mTransactionHandler.handleLaunchActivity(...);
          break;
        case ON_START:
          mTransactionHandler.handleStartActivity(...);
          break;
        case ON_RESUME:
          mTransactionHandler.handleResumeActivity(...);
          break;
        case ON_PAUSE:
          mTransactionHandler.handlePauseActivity(...);
          break;
        case ON_STOP:
          mTransactionHandler.handleStopActivity(...);
          break;
        case ON_DESTROY:
          mTransactionHandler.handleDestroyActivity(...);
          break;
        case ON_RESTART:
          mTransactionHandler.performRestartActivity(...);
          break;
      }
    }
  }
}


ダイアグラムの更新:



画像



最初のフレーム



最初のフレームのレンダリングにつながるメソッド呼び出しのシーケンスを見てみましょう。



  • ActivityThread。handleResumeActivity()
  • WindowManagerImpl。addView()
  • WindowManagerGlobal。addView()
  • ViewRootImpl。setView()
  • ViewRootImpl。requestLayout()
  • ViewRootImpl。scheduleTraversals()
  • 振付師。postCallback()
  • 振付師。scheduleFrameLocked()


振付師の方法。scheduleFrameLocked()は、キューMSG_DO_FRAMEのメッセージを



画像



処理するときMSG_DO_FRAMEのメッセージを、振付メソッドが呼び出されます。doFrame()は、ViewRootImplを呼び出します。doTraversal()は、メジャーパスレイアウトパスを渡し、最後にビュー階層通る最初の描画パス渡します。



画像



結論



システムがアプリケーションプロセスを作成するときに何が起こるかを高度に理解することから始めました。



画像



これで、「内部」で正確に何が起こるかがわかりました。



画像



次に、ユーザーがアプリケーションアイコンをタップしてから最初のアイコンが描画されるまで、前の投稿の図を接続しましょう。フレーム:



画像



全体像がわかったので、コールドスタートを適切に制御する方法を理解し始めることができます。次の投稿はそれについてです!またね。



All Articles