Rendu de la première image d'une application Android

image



Bonjour à tous! Cet article est une continuation de l' article sur une plongée en profondeur dans le processus de chargement et de lancement d'une application Android. Aujourd'hui, nous allons aller un peu plus loin et discuter du moment où l'Activité principale de l'application est lancée et le système doit rendre la première image. S'il vous plaît, sous le chat.



Suite à la documentation officielle, le processus de candidature en cours est responsable de l'exécution des étapes suivantes:



  1. Création d'un objet de la classe Application.
  2. Démarrez le thread principal (MainThread aka UiThread).
  3. Création de l'activité de départ, qui est spécifiée dans le manifeste.
  4. Expansion (inflation, gonflement) des vues. Autrement dit, la création de vues écrites dans le fichier xml.
  5. Disposition des tailles (View.measure ()) et placement (View.layout ()) des vues à l'écran.
  6. Exécution du rendu initial.


Une fois la première image dessinée, le processus système remplace la fenêtre d'arrière-plan affichée, en la remplaçant par l' activité d' application. L'utilisateur peut désormais interagir avec l'application.



image



Regardons maintenant de plus près toutes les étapes.



Début du flux principal



Dans le post précédent, nous avons appris:



  • , ActivityThread.main(), IPC- ActivityManagerService.attachApplication() system_server.
  • system_server IPC- ActivityThread.bindApplication(), BIND_APPLICATION MessageQueue .
  • Lorsque l'appel IPC à ActivityManagerService. attachApplication () terminé, ActivityThread. main () appelle Looper. loop () , qui bouclera indéfiniment (tant que l'application est en cours d'exécution) et traitera les messages entrant dans MessageQueue .
  • Le premier message à traiter est BIND_APPLICATION . À ce stade, la méthode ActivityThread sera appelée. handleBindApplication () , qui chargera l'APK et d'autres composants d'application.


image



Un point important: rien ne se passe dans le thread principal du processus d'application jusqu'à ce qu'un appel IPC à ActivityManagerService soit effectué. attachApplication () .



Planifier le lancement de l'activité



Voyons ce qui se passe dans le processus system_server après avoir appelé la méthode ActivityThread. 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;
  }
}


La chaîne qui est pertinente pour le lancement de l'activité est mAtmInternal. attachApplication (...) . La méthode appelle ActivityTaskManagerService. attachApplication () , qui à son tour appelle le 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 */
          )
        }
      }
    }
    ...
  }
}


Le code effectue les opérations suivantes:



  • Contourne chaque affichage.
  • Obtient la pile d'activités ciblées pour cet affichage.
  • Boucle sur chaque activité de la pile d'activités cible.
  • Si l'activité appartient à un processus en cours d'exécution, la méthode ActivityStackSupervisor est appelée. realStartActivityLocked () . Notez que le paramètre andResume sera vrai si l'activité est en haut de la pile.


Voici à quoi ressemble la méthode 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);
    ...
  }
}


Tous les appels de méthode que nous avons vus se produisent dans le processus system_server . ClientLifecycleManager. scheduleTransaction () effectue un appel IPC à ActivityThread. scheduleTransaction () dans le processus d'application qui appelle ClientTransactionHandler. scheduleTransaction () pour mettre en file d' attente le message 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
        );
    }
}


Lors du traitement du message EXECUTE_TRANSACTION , la méthode TransactionExecutor est appelée. exécuter () .



Vous pouvez maintenant mettre à jour le diagramme:



image



Lancement effectif de l'activité



TransactionExecutor. execute () appelle TransactionExecutor.

performLifecycleSequence () , qui effectue à son tour un rappel dans ActivityThread pour créer ( créer ), démarrer ( démarrer ) et reprendre ( reprendre ) l'activité:



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;
      }
    }
  }
}


Mise à jour du diagramme:



image



Première image



Jetons un coup d'œil à la séquence d'appels de méthode qui conduisent au rendu de la première image:



  • ActivityThread. handleResumeActivity ()
  • WindowManagerImpl. addView ()
  • WindowManagerGlobal. addView ()
  • ViewRootImpl. setView ()
  • ViewRootImpl. requestLayout ()
  • ViewRootImpl. horaireTraversals ()
  • Chorégraphe. postCallback ()
  • Chorégraphe. scheduleFrameLocked ()


Méthode chorégraphe. scheduleFrameLocked () met en file d'attente le message MSG_DO_FRAME :



image



Lors du traitement du message MSG_DO_FRAME , la méthode Choreographer est appelée. doFrame () , qui à son tour appelle ViewRootImpl. doTraversal () , qui passe la passe de mesure et la passe de mise en page , et enfin le premier dessin passe par la hiérarchie des vues:



image



Conclusion



Nous avons commencé avec un haut niveau de compréhension de ce qui se passe lorsque le système crée le processus de candidature:



image



nous savons maintenant ce qui se passe exactement «sous le capot»:



image



connectons maintenant les diagrammes du post précédent, à partir du moment où l'utilisateur appuie sur l'icône de l'application jusqu'à ce que le premier soit dessiné. frame:



image



Maintenant que nous avons l'image complète, nous pouvons commencer à comprendre comment contrôler correctement un démarrage à froid. Le prochain article en parlera! À plus.



All Articles