Android est comment il est carte Chorégraphe

avant-propos

Pour l'interface utilisateur Android est pas lisse problèmes, Google a proposé Project Butter système d'affichage Android ont été reconstruits. La reconstruction de trois points clés

  • VSynch de synchronisation verticale
  • Triple tampon Cache
  • Accueil Petits rats

Dans cet article, nous discutons principalement Chorégraphe, nous écrivons sur l'autre suivi.

chorégraphie

La grande expérience informatique écran d'affichage à travers la CPU - >  Synthèse GPU pixellisation - > Les affichages de dispositif d'affichage. Nous savons taux de rafraîchissement de l'appareil Android de 60 Hz est généralement une seconde 60 fois, une fois s'il établi a pas de problème lorsqu'il sera achevé en environ 16 cents miauler. Mais où une fois que le manque de coordination sera un problème dans la figure suivante

  • cpu calcul de la première période, l'opération de GPU, le dispositif d'affichage ne montre aucun problème
  • La deuxième période, la période d'affichage d'une image de dessin préparé, il n'y a pas de problème. calcul de la CPU est seulement prise en compte lorsque le cycle est sur le point d'extrémité
  • L'image du troisième cycle, en raison de l'entrée de la deuxième période lorsque les mains CPU tête de calcul ultérieur de la fin, entrant dans la troisième période de temps doit être affiché pas prêt, ce qui conduit à un tiers sur toute la période ou tout montrer période de la vidéo, qui semble être bloqué, hors du cadre! Les ingénieurs de Google appelé tube entier Jank retardé des avions militaires.

Ce n'est pas une petite chose, ah, comment le résoudre? Synchronisation verticale simplement, est de laisser le CPU ne prévoyez pas de calculer le temps, mais il n'y a pas de loi au début de chaque cycle commence à compter, cela a été suivi (comme indiqué ci-dessous) sur la méthodique et ordonnée. Le chorégraphe a rejoint la classe android4.1 et plus tard, nous allons voir comment il a griffé réalisé.

Tout d'abord, l'entrée

1.1 postCallbackDelayedInternal

ViewRoot la méthode doTravle () d'une telle ligne de code

mChoreographer.postCallback ( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

Cela signifie pour déclencher le fonctionnement de l'ensemble de la mise en page de mesure dessin Voir arbre. Plus de détails sur ViewRootImpl ne sont pas présentés ici.

Procédé suivant

  • public void postCallback (...);
  • public void postCallbackDelayed (...);
  • public void postFrameCallback (Callback FrameCallback);
  • public void postFrameCallbackDelayed (Rappel FrameCallback, longue delayMillis)

La finale appellera postCallbackDelayedInternal (), nous regardons la fonction de cette méthode.

 private void postCallbackDelayedInternal (int callbackType, l'action de l'objet, un jeton d'objet, de longues delayMillis) { synchronisée (mlock) { finale longue maintenant = SystemClock.uptimeMillis (); // Obtenez l'heure actuelle finale longue dueTime = maintenant + delayMillis; // expireront // va effectuer une action sur un tableau mCallback mCallbackQueues .addCallbackLocked (dueTime, action, jeton); // Si la demande d'enregistrement est arrivé à expiration sur le signal de synchronisation verticale si (dueTime < = Maintenant) { scheduleFrameLocked (maintenant); } Else { // Si pas expiré, l'utilisation d'un retard dans le gestionnaire de messages de transmission. Ce délai sera exécuté lorsque le message arrive à expiration. Message msg = mHandler.obtainMessage (MSG_DO_SCHEDULE_CALLBACK, action); msg.arg1 = callbackType; msg.setAsynchronous (true); mHandler.sendMessageAtTime (msg, dueTime); } } }

1.2 FrameHandler

Dans la section précédente, si l'exécution directe a expiré méthode scheduleFrameLocked (), si la transmission est pas effectuée sur l'utilisation mHandler (type FrameHandler) quelle est la valeur d'un MSG_DO_SCHEDULE_CALLBACK Le message. Comment effectuer après l'expiration. Cela dépend de la façon dont le traitement de FrameHandler.

 FrameHandler privé de classe finale étend Handler { FrameHandler publique (Looper looper) { Super (boucleur); } @Override handleMessage public void (message msg) { commutateur (msg.what) { cas MSG_DO_FRAME: doFrame (System.nanoTime (), 0); break; cas MSG_DO_SCHEDULE_VSYNC: doScheduleVsync (); break; cas MSG_DO_SCHEDULE_CALLBACK: // méthode postCallbackDelayedInternal () ne prend pas fin lorsque le temps est venu d'envoyer doScheduleCallback (msg.arg1); break; } } }

Nous pouvons voir que le code ci-dessus, FramHandler get valeur de la propriété whate MSG_DO_SCHEDULE_CALLBACK Quand je vais à effectuer doScheduleCallback (msg.arg1), méthode, passez à la prochaine suivi

1.3 Chorégraphie # doScheduleCallback

doScheduleCallback vide (int callbackType) { synchronisée (mlock) { if (! mFrameScheduled) { finale longue maintenant = SystemClock.uptimeMillis (); si (mCallbackQueues .hasDueCallbacksLocked (maintenant)) { scheduleFrameLocked (maintenant); } } } }

Cette méthode d'abord fait un jugement, mFrameSceduled est faux et retourne hasDueCallbacksLocked () Cette méthode est vrai, regardez le nom de méthode peut deviner si ce rappel a expiré, alors nous allons analyser cela. Si finalement il appellera scheduleFrameLocked sous la condition est satisfaite () Cette méthode, cette méthode Hey ne connaît pas? Oui, oui, cette méthode méthode postCallbackDelayedInternal () si l'expiration du puis exécuté directement. Il est temps de voir ce que l'intérieur de la méthode.

1,4 scheduleFrameLocked ()

private void scheduleFrameLocked (longtemps maintenant) { if (! mFrameScheduled) { mFrameScheduled = true; // drapeau ensemble indique une demande de programmer une trame suivante a été rendue. si (USE_VSYNC) { // Si en cours d'exécution sur le fil de boucleur, puis programmer la vsync immédiatement, // REACTIONS par ailleurs un message pour planifier la vsync du fil interface utilisateur // le plus tôt possible. / ** Traduire, le cas dans le thread principal, appelez immédiatement pour organiser la synchronisation verticale directe, sinon de fil non principal envoie un message dans le thread principal le plus tôt possible d'organiser une synchronisation verticale * / si (isRunningOnLooperThreadLocked ()) { scheduleVsyncLocked (); } Else { Message msg = mHandler.obtainMessage (MSG_DO_SCHEDULE_VSYNC); msg.setAsynchronous (true); mHandler.sendMessageAtFrontOfQueue (msg); } } Else { finale longue nextFrameTime = Math.max ( mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, maintenant); si (DEBUG_FRAMES) { Log.d (TAG, "Planification d'image suivante dans" + (nextFrameTime - maintenant) + "ms."); } Message msg = mHandler.obtainMessage (MSG_DO_FRAME); msg.setAsynchronous (true); mHandler.sendMessageAtTime (msg, nextFrameTime); } } }
  • Le but de cette méthode est arrangement très clair, et disposé immédiatement une synchronisation verticale immédiatement dès que possible. Disposer la synchronisation verticale est la condition USE_VSYNC est vrai, qui est, le dispositif prend en charge la synchronisation verticale
  • Dans le cas contraire, il envoie une période de synchronisation verticale retardée par un gestionnaire de messages arrangement de synchronisation verticale, c'est ce que le message MSG_DO_FRAME bloc de code de référence 1.2 est un message pour effectuer la méthode MSG_DO_FRAME doFrame () quoi.
  • Détail, lorsque la valeur mFrameScheduled est vrai quand il ne doit revenir directement pour demander le prochain rendu de trame, et si elle est fausse, l'exécution scheduleFrameLocked () pour continuer, et il est fixé à ture, à quel moment il est défini sur false ? Pour plus de détails, voir l'annexe II

Des dispositions spécifiques pour la synchronisation verticale est FrameDisplayEventReceiver sa classe est destinée à recevoir le signal vertical DisplayEventReceiver

 FrameDisplayEventReceiver privé de classe finale étend DisplayEventReceiver met en uvre Runnable { booléen mHavePendingVsync privé; longues mTimestampNanos privées; int mFrame privé; FrameDisplayEventReceiver publique (Looper looper, int vsyncSource) { Super (boucleur, vsyncSource); } @Override public void onVsync (longues timestampNanos, int builtInDisplayId, cadre int) { mTimestampNanos = timestampNanos; mFrame = cadre; Message msg = Message.obtain (mHandler, this); msg.setAsynchronous (true); // Message à asynchrone mHandler.sendMessageAtTime (msg, timestampNanos / TimeUtils.NANOS_PER_MS); } @Override public void run () { mHavePendingVsync = false; doFrame (mTimestampNanos, mFrame); } }

Après avoir reçu la méthode de rappel de signal de synchronisation verticale onVsync, qui utilisent la fonction de rappel de la courroie de transmission de gestionnaire (type Exécutable, lui-même hérité) le message, le dernier run () est également appelée doFrame (); (à ce sujet, ces informations de fonctionnement du détail logique du gestionnaire, Annexe ci-dessous en référence à un gestionnaire de messages de distribution

Ce message est mis à asynchrone (msg.setAsynchronous (true);) Cela signifie qu'il a le droit de préséance, la façon dont il a la priorité de celui-ci? En se référant au message de mode de l'Annexe III

En résumé, ajouter processus de rappel

En second lieu, la mise en uvre de

doFrame

 doFrame vide (longues frameTimeNanos, cadre int) { finale longue startNanos; synchronisée (mlock) { if (! mFrameScheduled) { retour // pas de travail } // heure actuelle startNanos = System.nanoTime (); // temps courant et un temps de synchronisation verticale finale longue jitterNanos = startNanos - frameTimeNanos; // différence de temps de synchronisation verticale et l'heure courante, si plus d'un cycle pour corriger cette si (jitterNanos > = MFrameIntervalNanos) { // obtenir le cycle d'interpolation reste toujours finale longue lastFrameOffset = jitterNanos% mFrameIntervalNanos; // reste du temps en cours moins l'étape précédente pour obtenir le dernier en tant que signal toujours le temps frameTimeNanos = startNanos - lastFrameOffset; } // temps de synchronisation verticale aussi un peu de temps pour organiser le prochain retour vertical direct si (frameTimeNanos <  mLastFrameTimeNanos) { scheduleVsyncLocked (); retour; } mFrameInfo.setVsync (intendedFrameTimeNanos, frameTimeNanos); mFrameScheduled = false; mLastFrameTimeNanos = frameTimeNanos; } try { Trace.traceBegin (Trace.TRACE_TAG_VIEW, "Chorégraphe # doFrame"); AnimationUtils.lockAnimationClock (frameTimeNanos / TimeUtils.NANOS_PER_MS); mFrameInfo.markInputHandlingStart (); doCallbacks (Choreographer.CALLBACK_INPUT, frameTimeNanos); mFrameInfo.markAnimationsStart (); doCallbacks (Choreographer.CALLBACK_ANIMATION, frameTimeNanos); mFrameInfo.markPerformTraversalsStart (); doCallbacks (Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); doCallbacks (Choreographer.CALLBACK_COMMIT, frameTimeNanos); } Enfin { AnimationUtils.unlockAnimationClock (); Trace.traceEnd (Trace.TRACE_TAG_VIEW); } si (DEBUG_FRAMES) { finales longues endNanos = System.nanoTime (); Log.d (TAG, "Frame" + cadre + ": Terminé, a pris" + (EndNanos - startNanos) * 0.000001f + "ms, temps de latence" + (StartNanos - frameTimeNanos) * 0.000001f + "ms."); } }
  • La première étape de correction juge
    • heure actuelle startNanos = System.nanoTime ();
    • A la recherche de l'heure et une différence de temps de synchronisation verticale: jitterNanos = startNanos - frameTimeNanos;
    • Une différence de temps de synchronisation verticale entre l'heure courante et si plus d'une période (jitterNanos > = MFrameIntervalNanos) pour corriger que
    • Et toujours prendre le cycle d'interpolation reste: lastFrameOffset = jitterNanos% mFrameIntervalNanos;
    • Le reste du temps en cours moins l'étape précédente pour obtenir la dernière comme toujours le temps de signal: frameTimeNanos = startNanos - lastFrameOffset;
    • Le temps de synchronisation verticale aussi un peu de temps pour organiser le prochain rendu: frameTimeNanos <  mLastFrameTimeNanos, retour direct
  • La seconde étape d'exécution de rappel  l'ordre d'exécution de rappel est la suivante:
    • Entrez l'heure la plus haute priorité CALLBACK_INPUT
    • CALLBACK_ANIMATION animation suivi
    • mise en page l'interface utilisateur CALLBACK_TRAVERSAL du tirage au sort à nouveau
    • CALLBACK_COMMIT modifications d'animation liées à la finale.

    2.2 doCallbacks ();

    • en CallbackQueue mCallbackQueues D'une certaine manière particulière le type de liste chaînée (entrée, l'animation, la mise en page, l'envoi) de
    • Retirez ensuite expiré Callback / runable effectuée

    Les mesures prises à effectuer

    Action CallbackRecord emballage, la liste à sens unique est disposée selon l'ordre du temps. Les mesures à prendre est effectuée par la méthode, peut être considéré comme la gestion de la classe CallBackQueue CallBack, comprenant en outre l'ajout d'action addCallbackLocked (), la suppression d'action removeCallbacksLocked (), s'il est élevé Anction hasDueCallbacksLocked (CallBackQueue extractDueCallbacksLocked ()) méthode.

     classe finale privée CallbackQueue { // tête de liste privé CallbackRecord mHead; // s'il a expiré action public boolean hasDueCallbacksLocked (longue maintenant) { retour mHead! = null && mHead.dueTime < = Maintenant; } // Obtenir l'action a expiré publique CallbackRecord extractDueCallbacksLocked (longue maintenant) { ... retourner callbacks; } // ajouter action addCallbackLocked public void (longue dueTime, l'action de l'objet, un jeton d'objet) { ... } // Action Supprimer public void removeCallbacksLocked (action objet, jeton d'objet) { ... } }

    La mise en uvre d'action

     pour (c = CallbackRecord callbacks; c = null ;! c = c.next) { c.run (frameTimeNanos); }

    Rappel à partir de la traverse CallBcakRecord, exécuté un par un.

    III Résumé

    • Chorégraphe étranger fournit d'autres méthodes postCallback, en fin de compte, ils sont tous internes pour mettre en uvre cette méthode en appelant postCallbackDelayedInternal () va faire deux choses principales
    • stockage d'action
    • la demande de verticale, une synchronisation verticale
    • Une correction de synchronisation verticale effectuée immédiatement action (callback / Exécutable).
    • Un type d'action peut être contenu d'action
    • Entrez l'heure la plus haute priorité CALLBACK_INPUT
    • CALLBACK_ANIMATION animation suivi
    • mise en page l'interface utilisateur CALLBACK_TRAVERSAL du tirage au sort à nouveau
    • CALLBACK_COMMIT modifications d'animation liées à la finale.
    • mécanisme d'examen Hanlder, je pense qu'il est le système Android pour lancer un gros moteur de points d'extrémité d'intérêt, gestionnaire effectuer la distribution des messages, et « mode asynchrone. »

    attaché

    Annexe, le gestionnaire exécute un message

    Ce qui suit est un gestionnaire de logique de distribution, le message sera de cible (type Handler) de traitement attribut msg.target.dispatchMessage (msg) obtenue après un message boucleur à exécuter dans MessageQueue ;;

     DispatchMessage public void (message msg) { // rappel quand msg est pas vide quand il est le rappel d'exécution directe msg est un objet Runnable si (msg.callback! = null) { handleCallback (msg); } Else { // puis remis mCallBack, il est un attribut du gestionnaire, Temps // Créer Handler peut choisir de passer un objet callback // retourne vrai quand callBack dans la représentation du temps handleMessage: Vrai si aucune manipulation supplémentaire est souhaitée (aucun autre traitement) si (mCallback! = null) { si (mCallback.handleMessage (msg)) { retour; } } // Lors du retour de traitement mCallback faux lorsque l'exécution avant d'aller Handler propre méthode handleMessage () handleMessage (msg); } }

    La logique clé annoté, résumé de distribuer la logique d'exécution de gestionnaire de message

  • Si le message de la méthode de rappel (runnable) la propriété est pas vide, appel () la course runable les exécute
  •  handleCallback vide de private static (message du message) { message.callback.run (); }

    Lorsque nous utilisons handler.post (Runnable r) r méthode est de régler l'heure pour le message de rappel

  • Dans les conditions ne sont pas réunies, si le gestionnaire lui-même de temps mCallback ne sera pas vide, le message au traitement mCallback, fin handlerMessage (). Cette propriété est créée lorsque le gestionnaire a passé. mCallback est de type CallBack, il est un gestionnaire d'interface interne est.
  •  {public interface Callback boolean handleMessage (message msg); }

    3. Lorsque messaga de callBak vide et gestionnaire de mCallBack vide quand il a remis sa méthode handlerMessage () est exécutée. Lorsque le message nous gestionnaire personnalisé peut remplacer cette méthode pour effectuer l'action appropriée.

    Attaché à deux, mFrameScheduled propriétés de l'effet

    • Lorsque callcack exécuté déterminera la propriété mFrameScheduled si elle est fausse qu'il n'y a pas d'arrangement pour rendre l'image suivante sur le retour direct est pas exécuté.
     doFrame vide (longues frameTimeNanos, cadre int) { finale longue startNanos; synchronisée (mlock) { if (! mFrameScheduled) { retour // pas de travail } ... ... mFrameScheduled = false; ... }
    • Dans le procédé scheduleFrameLocked (), la valeur est définie sur mFrameScheduled disposée demande montrant ture pour rendre l'image suivante. Si ce temps est vrai mFrameScheduled a dit qu'il avait pris des dispositions pour l'image suivante, il retourne, pas le chaos!

    Joint à trois, le mécanisme gestionnaire de mode asynchrone

    effet

    Le rôle du « mode asynchrone » est la priorité, un message asynchrone ont le droit de priorité en mode asynchrone.

    usage

    MessageQueue utiliser la méthode postSyncBarrier () pour ajouter une barrière, procédé removeSyncBarrier () enlever cette barrière est utilisée par paires de deux.

    le principe

    • Procédé postSyncBarrier messageQueued l'ajout d'un attribut cible à la tête du message est MessageQueue null
    • MessageQueue suivant () est nulle quand il s'agit de cibler le message quand il sortira un message « message asynchrone » dans la liste, tout en ignorant message normal, à looper autre processus de distribution.
     Message suivant () { ... for (;;) { si (nextPollTimeoutMillis! = 0) { Binder.flushPendingCommands (); } nativePollOnce (ptr, nextPollTimeoutMillis); synchronisée (ce) { // Essayez de récupérer le message suivant. Retour si trouvé. finale longue maintenant = SystemClock.uptimeMillis (); Message prevMsg = null; Message msg = mMessages; si (msg! = null && msg.target == null) { // Bloqués par une barrière. Trouver la prochaine messagin asynchrone la file d'attente. do { prevMsg = msg; msg = msg.next; } Bien que (Msg = null && msg.isAsynchronous ()!); ...} retourner msg; } ...

    Enfin, l'architecture et des informations connexes

    Mode de réception:

    Regarder + réponse privée lettre, libre accès « données Andrews »!

    Android pour obtenir à recevoir l'architecture avancée de l'information, le code source, notes, vidéo. Interface utilisateur principale, optimisation des performances, des cours d'architecte, NDK, développement hybride (ReactNative + Weex) applet micro lettre, pratique avancée Flutter Android tous les aspects de la technologie.

    Mode de lecture de contrôle: revêtement amincissement définissant jusqu'à Dragon headed
    Précédent
    « Parmi Compass » personnages originaux qui apparaissent dans le rôle du renseignement annoncé
    Prochain
    Jouez en mode contrôle: version sophistiquée noire du 78
    Que Zhao Liying était la fille du roi Gong Li est devenu le plus beau pays qui a toujours que sa
    Chine Location automobile commercialisation nationale de nouvelles façons d'utiliser les données pour créer des contacts de marketing à fort potentiel
    Contrôle de jeu Mod: force gto zaguchicilia
    Aux yeux des joueurs japonais qui jeux sont les meilleurs dans le monde?
    Pour vous dire, Lu Han Guan Gong Xiaotong ouvert Kaka qui est le bénéficiaire?
    Zhang Yimou groupe familial rare sur le tapis rouge à la fin de sa belle-mère Zhang Chen et Xiao Hua Ting pairs Qui se souvient?
    Contrôle de lecture en mode: HGUC corps spécifique MS-14JG Bailang
    Tencent anciens employés à cause de plagiat a été signalé, la fin du marché Voyage dans un dilemme cottage
    Sans un ennemi puissant, il n'y aura pas grand héros. L'un des meilleurs méchant DC
    2017 membres Coupe Badminton Chine Sailuo Lan 4A tenue avec succès la gare de Pékin
    Télécharger AndroidLibrary à JCenter: Comment faire votre propre code est élégant citer d'autres