Значение сообщений хореографа в Logcat
Я установил последние версии SDK (API 16)
и получил последнюю ADT. Теперь я вижу эти сообщения в logcat, в которых я совершенно уверен, что раньше не видел. У кого-нибудь есть идеи по этому поводу?
06-29 23: 11: 17.796: Я / Хореограф (691): пропущено 647 кадров! Приложение может выполнять слишком много работы в своем основном потоке.
Я выполнил поиск и нашел эту ссылку: http://developer.android.com/reference/android/view/Choreographer.html. Это новый класс, представленный в API 16.
Мне нужно знать, как я могу определить, какую "слишком большую работу" может выполнять мое приложение, так как вся моя обработка выполняется в AsyncTask
s.
5 ответов
Choreographer позволяет приложениям подключаться к vsync и правильно рассчитывать время, чтобы повысить производительность.
Android-анимация для внутреннего просмотра использует Choreographer для той же цели: для правильного определения времени анимации и, возможно, для повышения производительности.
Так как Choreographer сообщается о каждом событии vsync, я могу сказать, не завершается ли один из Runnables, переданных с помощью Choreographer.post * apis, за один кадр, что приводит к пропуску кадров.
В моем понимании хореограф может только обнаружить пропуск кадра. Он не может сказать, почему это происходит.
Сообщение "Приложение может выполнять слишком много работы в своем основном потоке". может вводить в заблуждение.
Я опоздал на вечеринку, но, надеюсь, это полезное дополнение к другим ответам здесь...
Ответ на вопрос / tl:dr;
Мне нужно знать, как я могу определить, какую "слишком большую работу" может выполнять мое приложение, поскольку вся моя обработка выполняется в AsyncTasks.
Ниже приведены все кандидаты:
- IO или дорогостоящая обработка в главном потоке (загрузка чертежей, раздувание макетов и настройка
Uri
наImageView
все составляют IO на основной ветке) - Рендеринг большой / сложный / глубокий
View
иерархий - Признать недействительными большие порции
View
иерархия - Дорого
onDraw
методы на заказView
"s - Дорогие расчеты в анимации
- Запуск "рабочих" потоков с слишком высоким приоритетом, чтобы считаться "фоновым" (
AsyncTask
по умолчанию являются "фоновыми",java.lang.Thread
нет) - Генерация большого количества мусора, в результате чего сборщик мусора "останавливает мир", включая основной поток, пока он очищает
Чтобы действительно определить конкретную причину, вам нужно профилировать свое приложение.
Более детально
Я пытался понять хореографа, экспериментируя и глядя на код.
Документация Хореографа открывается "Координирует время анимации, ввода и рисования". что на самом деле хорошее описание, но остальное переоценивает анимацию.
Хореограф фактически отвечает за выполнение 3-х типов обратных вызовов, которые выполняются в следующем порядке:
- обратные вызовы обработки ввода (обработка ввода пользователя, такого как сенсорные события)
- анимационные обратные вызовы для анимации между кадрами, обеспечивающие стабильное время начала кадра для любой / всех запущенных анимаций. Выполнение этих обратных вызовов 2-й означает, что любые вычисления, связанные с анимацией (например, изменение позиций просмотра), уже были сделаны к тому времени, когда вызывается третий тип обратного вызова...
- просмотр обратных вызовов для отрисовки иерархии представления.
Цель состоит в том, чтобы сопоставить частоту повторного отображения недействительных представлений (и анимации анимации) с vsync экрана - обычно 60 кадров в секунду.
Предупреждение о пропущенных кадрах выглядит как запоздалая мысль: сообщение заносится в журнал, если один проход через 3 шага более чем в 30 раз превышает ожидаемую длительность кадра, поэтому наименьшее число, которое вы можете увидеть в сообщениях журнала, - это "пропущенные 30 кадров"; Если каждый проход занимает на 50% больше времени, чем нужно, вы все равно пропустите 30 кадров (непослушный!), Но вы не будете предупреждены об этом.
Из трех этапов ясно, что предупреждение может вызывать не только анимация: аннулирование значительной части большого View
иерархия или View
со сложным методом onDraw может быть достаточно.
Например, это вызовет предупреждение несколько раз:
public class AnnoyTheChoreographerActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_linear_layout);
ViewGroup root = (ViewGroup) findViewById(R.id.root);
root.addView(new TextView(this){
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
long sleep = (long)(Math.random() * 1000L);
setText("" + sleep);
try {
Thread.sleep(sleep);
} catch (Exception exc) {}
}
});
}
}
... который производит ведение журнала следующим образом:
11-06 09:35:15.865 13721-13721/example I/Choreographer﹕ Skipped 42 frames! The application may be doing too much work on its main thread.
11-06 09:35:17.395 13721-13721/example I/Choreographer﹕ Skipped 59 frames! The application may be doing too much work on its main thread.
11-06 09:35:18.030 13721-13721/example I/Choreographer﹕ Skipped 37 frames! The application may be doing too much work on its main thread.
Вы можете увидеть из стека во время onDraw
что хореограф участвует независимо от того, анимируете ли вы:
в примере.AnnoyTheChoreographerActivity$1.onDraw(AnnoyTheChoreographerActivity.java:25) в android.view.View.draw (View.java:13759)
... довольно много повторений...
на android.view.ViewGroup.drawChild(ViewGroup.java:3169) на android.view.ViewGroup.dispatchDraw(ViewGroup.java:3039) на android.view.View.draw(View.java:13762) на android.widget.FrameLayout.draw(FrameLayout.java:467) на com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2396) на android.view.View.getDisplayList(View.java:12710) на android.view.View.getDisplayList(View.java:12754) в android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1144) в android.view.ViewRootImpl.draw(ViewRootImpl.java:2273) в android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2145) в android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1956) в android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:11un.RoN.Traun $ и в $) (ViewRootImpl.java:4472) на android.view.Choreographer$CallbackRecord.run(Choreographer.java:725) на android.view.Choreographer.doCallbacks(Хореограф.java: 555) на android.view.Choreographer.doFra reographer.java:525) в android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711) в android.os.Handler.handleCallback(Handler.java:615) в android.os.Handler.dispatchMessage(Handler.j):92) на android.os.Looper.loop(Looper.java:137) на android.app.ActivityThread.main(ActivityThread.java:4898)
Наконец, если есть конкуренция со стороны других потоков, которые уменьшают объем работы, которую может выполнить основной поток, вероятность пропуска кадров резко возрастает, даже если вы фактически не выполняете работу в основном потоке.
В этой ситуации может показаться вводящим в заблуждение предположение о том, что приложение делает слишком много в главном потоке, но Android действительно хочет, чтобы рабочие потоки работали с низким приоритетом, чтобы предотвратить голодание основного потока. Если ваши рабочие потоки имеют низкий приоритет, единственный способ вызвать предупреждение Choreographer - это сделать слишком много в главном потоке.
Это если информационное сообщение, которое может появиться в вашем LogCat во многих ситуациях.
В моем случае это произошло, когда я программно надувал несколько видов из файлов макета XML. Сообщение само по себе безвредно, но может быть признаком более поздней проблемы, которая будет использовать всю оперативную память, которую разрешено использовать вашему приложению, и вызвать мегазлое Force Close. Я вырос как разработчик, которому нравится видеть его журнал WARN/INFO/ERROR Free.;)
Итак, это мой собственный опыт:
Я получил сообщение:
10-09 01:25:08.373: I/Choreographer(11134): Skipped XXX frames! The application may be doing too much work on its main thread.
... когда я создавал свой собственный "сверхсложный многосекционный список", надувая представление из XML и заполняя его поля (изображения, текст и т. д.) данными, полученными из ответа REST / Веб-сервис JSON (без возможности подкачки страниц) эти представления будут действовать как строки, заголовки подразделов и заголовки разделов, добавляя их все в правильном порядке к LinearLayout (с вертикальной ориентацией внутри ScrollView). Все это для имитации listView с интерактивными элементами... но это уже другой вопрос.
Как ответственный разработчик, вы хотите сделать приложение действительно эффективным с системными ресурсами, поэтому для списков (когда ваши списки не так сложны) лучше всего использовать ListActivity или ListFragment с загрузчиком и заполнять ListView с помощью адаптера, это предположительно более эффективно, на самом деле это так, и вы должны делать это все время, опять же... если ваш список не так сложен.
Решение: я реализовал разбиение на страницы в своем веб-сервисе REST/JSON, чтобы предотвратить "большие размеры ответов", и обернул код, который добавил представления "строк", "заголовков разделов" и "заголовков подразделов" в AsyncTask, чтобы сохранить Main Нить классная.
Итак... Я надеюсь, что мой опыт поможет кому-то еще, кто взломает голову этим информационным сообщением.
Счастливого взлома!
Обычно это происходит при отладке с использованием эмулятора, который в любом случае работает медленно.
В моем случае у меня есть эти сообщения, когда я показываю панель действий Шерлока inderterminate индикатор выполнения. Так как это не моя библиотека, я решил скрыть результаты работы хореографа.
Вы можете скрыть выходные данные Choreographer в представлении Logcat, используя это выражение фильтра:
тег:^((?! Хореограф).*)$
Я использовал регулярное выражение, объясненное в другом месте: Регулярное выражение для соответствия строке, которая не содержит слова?