Choreographer
Class Overview
Coordinates the timing of animations, input and drawing.
The choreographer receives timing pulses (such as vertical synchronization) from the display subsystem then schedules work to occur as part of rendering the next display frame.
Applications typically interact with the choreographer indirectly using higher level abstractions in the animation framework or the view hierarchy. Here are some examples of things you can do using the higher-level APIs.
- To post an animation to be processed on a regular time basis synchronized with display frame rendering, use start() .
- To post a Runnable to be invoked once at the beginning of the next display frame, use postOnAnimation(Runnable) .
- To post a Runnable to be invoked once at the beginning of the next display frame after a delay, use postOnAnimationDelayed(Runnable, long) .
- To post a call to invalidate() to occur once at the beginning of the next display frame, use postInvalidateOnAnimation() or postInvalidateOnAnimation(int, int, int, int) .
- To ensure that the contents of a View scroll smoothly and are drawn in sync with display frame rendering, do nothing. This already happens automatically. onDraw(Canvas) will be called at the appropriate time.
However, there are a few cases where you might want to use the functions of the choreographer directly in your application. Here are some examples.
- If your application does its rendering in a different thread, possibly using GL, or does not use the animation framework or view hierarchy at all and you want to ensure that it is appropriately synchronized with the display, then use postFrameCallback(Choreographer.FrameCallback) .
- . and that’s about it.
Each Looper thread has its own choreographer. Other threads can post callbacks to run on the choreographer but they will run on the Looper to which the choreographer belongs.
Источник
Русские Блоги
Android Choreographer
вступление
На самом деле, я не обратил внимания на хореографию, в процессе делужирования демонстрации приложения случайно нашел журнал:
I/Choreographer: Skipped 1201 frames! The application may be doing too much work on its main thread.
Это системный журнал, что означает, что основной нить слишком много, что приводит к кадру. Внезапно обнаружил, что хореограф полезен, может использоваться для мониторинга производительности приложений, коробки, скорости кадра и т. Д., Настолько определяется, что требуется некоторое время для изучения.
Вступление
Класс хореографа расположен под пакетом Android.View, является последним классом, который является механизмом, который начинает присоединиться к Android 4.1 (уровень API = 16). Хореограф Литерал — это «посадка, книга», из официальной документации, вы можете получить следующую важной информацией:
- Координировать анимацию, ввод и время загрузки.
- Хореограф принимает временные импульсы из подсистемы дисплея, такой как сигнал VSync, а затем расплачивает рендеринг следующего кадра.
- Применения, как правило, не взаимодействуют напрямую с хореографом, но для использования абстрактных API на более высоком уровне в кадре анимации или просмотр иерархии.
- Существуют также несколько сцен, которые используют хореограф непосредственно в приложении. Если приложение оказывает в разных потоках, вы можете использовать GL, без анимации Framework или просмотреть иерархию, вам необходимо убедиться, что вам нужно сделать синхронизацию, вы можете назвать хореографа Отказ postFrameCallback(Choreographer.FrameCallback) метод.
- Каждая нить петли имеет свой собственный хореограф, и обратный вызов, отправленный другими потоками, может работать только на потоке петли, которая соответствует хореографу.
Анализ источника
Исходный код хореографа основан на Android 7.1.1, а другая версия исходного кода может варьироваться.
В курсе хореографа есть петлер и переменная рамкина. Рамкандлер наследует от обработчика, понимая механизм сообщений Android, естественным образом, зная, что обработчик нуждается в Looper для планирования сообщений.
Рамкандлер — это внутренний класс хореографа, который определяется следующим образом:
Реализация FrameHandler очень проста, только три типа сообщений, конкретная постоянная идентификация:
Следующий код создает CallbackQueue, массив емкости для хранения 4 различных обратных вызовов.
В частности, я могу знать входную анимацию, макет, операцию по отправке, по вводом обратного вызова, обратного обратного вызова, обратного вызова обхода, Commit Callback, соответственно.
Получить экземпляр хореографа
Примечание. Очевидно, что вышеизложенное также упомянуло, что каждый поток имеет свой собственный хореограф, поэтому он использует здесь нитокнокальный механизм, а поток должен иметь петлитель, в противном случае механизм сообщения не может быть выполнен.
О внедрении ThreadLocal код выглядит следующим образом:
Логика кода очень четкая, что означает использование конструктора хореографа для создания другого объекта хореографа для каждого потока.
Во-первых, таблица цепи реализована для инкапсуляции обратного вызова, которая используется в качестве целевого пула CallbackRecord, а также дизайн объекта сообщения в аналогичном механизме сообщений. Кроме того, в соответствии с токен, обратный вызов — это родительский или хранилище, отличительные условия token == FRAME_CALLBACK_TOKEN Потому что весь FrameCallback должен держать следующим образом:
Проще говоря, CallbackQueue — это класс работы CallbackRecord, обеспечивающий серию методов чтения, добавления, удаления CallBackRecord, что позволяет легко работать, следующим образом
- public CallbackRecord extractDueCallbacksLocked(long now)
- public void addCallbackLocked(long dueTime, Object action, Object token)
- public void removeCallbacksLocked(Object action, Object token)
Внутренний класс framedisplayeventreceiver.
В конструкторе Chandographer выше при использовании механизма VSync создается объект framedisplayeventreceiver, в основном используется для приема сигналов visync.
Частота сигнала VSync составляет 60 Гц, которая представляет собой сигнал VSync каждые 16,6 мс, запускает рендеринг пользовательского интерфейса. Если каждый рендеринг может быть завершен, частота кадров может достигать 60FPS (кадра в секунду), основанной на теории визуального павильона человека, 60fps гладкий эффект.
Когда частота кадров нормальна, как показано ниже:
Если кадр не может завершить рендуринг в пределах 16,6 мс (обычно из-за сложности, трудоемкого времени, чрезмерного рисунка и т. Д.), приведет к тому, что картина будет не поддаваться, для чувства пользователя есть коробка, если этот кадр занимает следующий N 16.6 MS Time, так называемая скованая рамка, которая указывает на то, что n рама теряется. Схема выглядит следующим образом:
Вернуться к теме, framedisplayeventreceiver наследует от DisplayEventreceiver и реализует Runnable, определяемый следующим образом
Когда вы получаете сигнал VSync, срабатывает следующий обратный вызов.
Там, где Timestampnanos представляет время получения сигнала, блок наносекунды; рамка представляет количество кадров и увеличивается с каждым сигналом VSYNC.
Наиболее важной логикой в OnVSync Callback — это инкапсулировать FramedInsPlayEventreceiver в сообщение и отправить его через механизм сообщения Android.
Поскольку framedisplayeventreceiver представляет собой прогонтелю, его соответствующий прогон реализован как
MHAVEPENDINDVSYNC — это переменная логотипа, указывая на то, что в то же время есть только одно событие сигнала VSync.
doFrame(mTimestampNanos, mFrame); Это реальная логика обработки после получения сигнала VSync, который будет в порядке.
Этот интерфейс вызывается на новом кадре, параметр является наносекундой, указывая, что время, когда этот кадр начинает рендер, обратите внимание на этот триггер обратного вызова на теме петлиной темы хореографа.
Отправьте обратный вызов, чтобы сделать его выполненным следующим кадром, самый простой вызов:
Обратите внимание, что второй параметр указывается, отправляя Runnable. Анализ анализируется в CallbeChoreCord, чтобы различать проводимый или FRAMECALLBACK в соответствии с токеном. Следующий postCallbackDelayed Реализация заключается в следующем:
В основном для проверки типа действия и обратного вызова callbacktype указал только четыре типа (callback_input, callback_animation, callback_traversal, callback_commit), постоянные значения определяются как 0, 1, 2, 3, а другие — это незаконные типы. Здесь заранее, тип обратного вызова FrameCallback использует Callback_animation.
Следующий postCallbackDelayedInternal Реализация:
Основная логика выше написана очень ясно в комментарии, scheduleFrameLocked Реализация:
Пожалуйста, смотрите заметки для конкретных процессов. doFrame Процесс:
Давайте посмотрим исходный код Docallbacks:
Общий процесс состоит в том, чтобы найти соответствующую CallbackQueue в соответствии с типом обратного вызова Callbacktype, а затем пересекайте таблицу цепи, выньте каждую CallbackRecord и выполните свой метод прогона:
Процесс обратного вызова будет по-настоящему выполнен в прогоне. После завершения обратного вызова Callbackrecord будет переработан. recycleCallbackLocked(callbacks) середина.
Кроме того, существует большое количество аннотаций для типа Callback_Commit, которое в основном, если время рендеринга текущего кадра превышает два кадра (2 * 16,6 мс), переключите время назад к предыдущему времени сигнала Visync. Например, на следующем рисунке показана ось времени, в которой 16, 32, 48, 64 представляет собой интервал времени одного рама, а также является временным интервалом сигнала Visync.
Если кадр должен обрабатывать обратный вызов на 16, из-за таймаута рендеринга он был задержан до 52 для ответа. Интервал времени составляет 36 (52-16), и превышено стандартное время двух кадров, время этого кадра исправлено на 32. Что касается причин, говорится, что проблема валюаниматора, ожидая отсутствующей.
Предыдущий отметил, что хореограф предоставляет интерфейс FrameCallback, давайте посмотрим, как он представлен и обрабатывается:
Сначала отправьте FrameCallback:
Продолжить звонок postFrameCallbackDelayed :
Обратите внимание, что frameCallback использует тип обратного вызова для Callback_animation и использует специальный токен (Frame_Callback_token) для идентификации frameCallback. postCallbackDelayedInternal Когда обычный обратный вызов был проанализирован, следующий процесс такой же, просто отличает его при окончательной обработке.
Вышеуказанное из исходного кода обратный вызов (обычный обратный вызов и FRAMECALLBACK) будет отправлен из процесса отправки в процесс, он все еще немного запутанно, следующее является блок-схемой, которая может четко понять его поток обработки :
Соответствующий Choreographer также предоставляет два способа удалить обратный вызов:
Хореограф ассоциирует с видом
Объект хореографа создается в конструкторе ViewRootimpl:
Он работает в основной нити.
существовать scheduleTraversals() Методы Хореограф отправляет обратный вызов Callback_traversal:
Давайте посмотрим на реализацию MTRavernnable
PerfortTraversals () будут вызываться в дотраверов (), и вы будете выполнять представление и подзлыми, макет и процессы рисования.
Таким образом, хореограф можно использовать для отслеживания производительности просмотра.
Сценарий приложений
Принцип хореографа понимает, что для его использования наиболее распространенным является использование его для мониторинга производительности приложений, коробки и частоте кадров.
Помните интерфейс FrameCallback, предоставленный хореографом? Вы можете настроить класс FPSmonitor, унаследованных от FrameCallback для мониторинга в форме кадра.
Затем используйте PostframeCallback Choreographarf Callback (обратный вызов FrameCallback), чтобы мы позвонили нашему пользовательскому FrameCallback при рендеринге, вы можете реализовать какую-то логику обнаружения в doframe.
Источник
Meaning of Choreographer messages in Logcat [duplicate]
I installed the latest versions of SDK (API 16) and got the latest ADT. I’m now seeing these messages in the logcat, that I’m quite sure, I haven’t seen before. Does anyone have an idea about this?
06-29 23:11:17.796: I/Choreographer(691): Skipped 647 frames! The application may be doing too much work on its main thread.
I did a search and found this link: http://developer.android.com/reference/android/view/Choreographer.html. This is a new class introduced in API 16.
I need to know how I can determine what «too much work» my application may be doing as all my processing is done in AsyncTask s.
5 Answers 5
Choreographer lets apps to connect themselves to the vsync, and properly time things to improve performance.
Android view animations internally uses Choreographer for the same purpose: to properly time the animations and possibly improve performance.
Since Choreographer is told about every vsync events, it can tell if one of the Runnables passed along by the Choreographer.post* apis doesn’t finish in one frame’s time, causing frames to be skipped.
In my understanding Choreographer can only detect the frame skipping. It has no way of telling why this happens.
The message «The application may be doing too much work on its main thread.» could be misleading.
I’m late to the party, but hopefully this is a useful addition to the other answers here.
Answering the Question / tl:dr;
I need to know how I can determine what «too much work» my application may be doing as all my processing is done in AsyncTasks.
The following are all candidates:
- IO or expensive processing on the main thread (loading drawables, inflating layouts, and setting Uri ‘s on ImageView ‘s all constitute IO on the main thread)
- Rendering large/complex/deep View hierarchies
- Invalidating large portions of a View hierarchy
- Expensive onDraw methods in custom View ‘s
- Expensive calculations in animations
- Running «worker» threads at too high a priority to be considered «background» ( AsyncTask ‘s are «background» by default, java.lang.Thread is not)
- Generating lots of garbage, causing the garbage collector to «stop the world» — including the main thread — while it cleans up
To actually determine the specific cause you’ll need to profile your app.
More Detail
I’ve been trying to understand Choreographer by experimenting and looking at the code.
The documentation of Choreographer opens with «Coordinates the timing of animations, input and drawing.» which is actually a good description, but the rest goes on to over-emphasize animations.
The Choreographer is actually responsible for executing 3 types of callbacks, which run in this order:
- input-handling callbacks (handling user-input such as touch events)
- animation callbacks for tweening between frames, supplying a stable frame-start-time to any/all animations that are running. Running these callbacks 2nd means any animation-related calculations (e.g. changing positions of View’s) have already been made by the time the third type of callback is invoked.
- view traversal callbacks for drawing the view hierarchy.
The aim is to match the rate at which invalidated views are re-drawn (and animations tweened) with the screen vsync — typically 60fps.
The warning about skipped frames looks like an afterthought: The message is logged if a single pass through the 3 steps takes more than 30x the expected frame duration, so the smallest number you can expect to see in the log messages is «skipped 30 frames»; If each pass takes 50% longer than it should you will still skip 30 frames (naughty!) but you won’t be warned about it.
From the 3 steps involved its clear that it isn’t only animations that can trigger the warning: Invalidating a significant portion of a large View hierarchy or a View with a complicated onDraw method might be enough.
For example this will trigger the warning repeatedly:
. which produces logging like this:
You can see from the stack during onDraw that the choreographer is involved regardless of whether you are animating:
at example.AnnoyTheChoreographerActivity$1.onDraw(AnnoyTheChoreographerActivity.java:25) at android.view.View.draw(View.java:13759)
. quite a bit of repetition .
at android.view.ViewGroup.drawChild(ViewGroup.java:3169) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3039) at android.view.View.draw(View.java:13762) at android.widget.FrameLayout.draw(FrameLayout.java:467) at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2396) at android.view.View.getDisplayList(View.java:12710) at android.view.View.getDisplayList(View.java:12754) at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1144) at android.view.ViewRootImpl.draw(ViewRootImpl.java:2273) at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2145) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1956) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1112) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4472) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725) at android.view.Choreographer.doCallbacks(Choreographer.java:555) at android.view.Choreographer.doFrame(Choreographer.java:525) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711) at android.os.Handler.handleCallback(Handler.java:615) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4898)
Finally, if there is contention from other threads that reduce the amount of work the main thread can get done, the chance of skipping frames increases dramatically even though you aren’t actually doing the work on the main thread.
In this situation it might be considered misleading to suggest that the app is doing too much on the main thread, but Android really wants worker threads to run at low priority so that they are prevented from starving the main thread. If your worker threads are low priority the only way to trigger the Choreographer warning really is to do too much on the main thread.
Источник