Android Logcat 中 Choreographer 消息的含义
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11266535/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Meaning of Choreographer messages in Logcat
提问by Code Poet
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?
我安装了最新版本SDK (API 16)
并获得了最新的 ADT。我现在在 logcat 中看到这些消息,我很确定,我以前从未见过。有没有人有这个想法?
06-29 23:11:17.796: I/Choreographer(691): Skipped 647 frames! The application may be doing too much work on its main thread.
06-29 23:11:17.796:I/Choreographer(691):跳过647帧!应用程序可能在其主线程上做了太多工作。
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.
我做了一个搜索,找到了这个链接:http: //developer.android.com/reference/android/view/Choreographer.html。这是 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.
我需要知道如何确定我的应用程序可能在做什么“太多工作”,因为我的所有处理都是在AsyncTask
s 中完成的。
采纳答案by CuriousChettai
Choreographer lets apps to connect themselves to the vsync, and properly time things to improve performance.
Choreographer 让应用程序将自己连接到 vsync,并正确安排时间以提高性能。
Android view animations internally uses Choreographer for the same purpose: to properly time the animations and possibly improve performance.
Android 视图动画在内部使用 Choreographer 用于相同目的:正确计时动画并可能提高性能。
Since Choreographer is told about every vsync events, I can tell if one of the Runnables passed along by the Choreographer.post* apis doesnt finish in one frame's time, causing frames to be skipped.
由于 Choreographer 被告知每个 vsync 事件,我可以判断 Choreographer.post* apis 传递的 Runnable 之一是否没有在一帧的时间内完成,从而导致跳过帧。
In my understanding Choreographer can only detect the frame skipping. It has no way of telling why this happens.
在我的理解 Choreographer 只能检测跳帧。它无法说明为什么会发生这种情况。
The message "The application may be doing too much work on its main thread." could be misleading.
消息“应用程序可能在其主线程上做了太多工作。” 可能会产生误导。
回答by Stevie
I'm late to the party, but hopefully this is a useful addition to the other answers here...
我参加聚会迟到了,但希望这是对这里其他答案的有用补充......
Answering the Question / tl:dr;
回答问题 / 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.
我需要知道如何确定我的应用程序可能在做什么“太多工作”,因为我的所有处理都是在 AsyncTasks 中完成的。
The following are all candidates:
以下是所有候选人:
- IO or expensive processing on the main thread (loading drawables, inflating layouts, and setting
Uri
's onImageView
'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 customView
'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
- 主线程上的 IO 或昂贵的处理(加载可绘制、膨胀布局和设置
Uri
的 onImageView
都构成主线程上的 IO) - 渲染大/复杂/深
View
层次结构 - 使
View
层次结构的大部分无效 onDraw
custom 中View
的昂贵方法- 动画中的昂贵计算
- 在过高的优先级运行“工人”线程被认为是“背景”(
AsyncTask
的是‘背景’在默认情况下,java.lang.Thread
是不是) - 产生大量垃圾,导致垃圾收集器在清理时“停止世界”——包括主线程
To actually determinethe 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.
我一直试图通过试验和查看代码来理解 Choreographer 。
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.
Choreographer 的文档以“协调动画、输入和绘图的时间”开头。这实际上是一个很好的描述,但其余的继续过分强调动画。
The Choreographer is actually responsible for executing 3 types of callbacks, which run in this order:
Choreographer 实际上负责执行 3 种类型的回调,它们按以下顺序运行:
- 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.
- 输入处理回调(处理用户输入,例如触摸事件)
- 用于帧间补间的动画回调,为正在运行的任何/所有动画提供稳定的帧开始时间。运行这些回调 2nd 意味着在调用第三种类型的回调时,任何与动画相关的计算(例如改变视图的位置)都已经完成......
- 用于绘制视图层次结构的视图遍历回调。
The aim is to match the rate at which invalidated views are re-drawn (and animations tweened) with the screen vsync - typically 60fps.
目的是将无效视图重新绘制(和补间动画)的速率与屏幕 vsync 相匹配 - 通常为 60fps。
The warning about skipped frames looks like an afterthought: The message is logged if a singlepass 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 30frames"; If eachpass takes 50% longer than it should you will still skip 30 frames (naughty!) but you won't be warned about it.
关于跳过帧的警告看起来像是事后的想法:如果单次通过 3 个步骤的时间超过预期帧持续时间的 30 倍,则会记录该消息,因此您可以期望在日志消息中看到的最小数字是“跳过30帧” ; 如果每次通过的时间比应有的时间长 50%,您仍然会跳过 30 帧(太调皮了!),但您不会收到警告。
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.
从涉及的 3 个步骤中可以清楚地看出,不仅是动画可以触发警告:使大型View
层次结构的重要部分或View
使用复杂的 onDraw 方法无效可能就足够了。
For example this will trigger the warning repeatedly:
例如,这将反复触发警告:
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) {}
}
});
}
}
... which produces logging like this:
...产生这样的日志:
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.
You can see from the stack during onDraw
that the choreographer is involved regardless of whether you are animating:
您可以从堆栈中看到onDraw
,无论您是否在制作动画,都涉及编舞:
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)
在 example.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) 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) 在 android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1144) 在 android.view.ViewRootImpl.draw(ViewRootImpl.java:2273) 在 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$runnable. (ViewRootImpl.java:4472) 在 android.view.Choreographer$CallbackRecord.run(Choreographer.java:725) 在 android.view.Choreographer.doCallbacks(Choreographer.java:555) 在 android.view.Choreographer.doFrame(Choreographer.java:525) 在 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) 在 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 priorityso 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.
在这种情况下,建议应用程序在主线程上执行过多操作可能会被认为具有误导性,但Android 确实希望工作线程以低优先级运行,以便防止它们饿死主线程。如果您的工作线程是低优先级,触发编排警告的唯一方法实际上是在主线程上做太多事情。
回答by Oscar Salguero
This if an Info message that could pop in your LogCat on many situations.
如果在许多情况下可能会在您的 LogCat 中弹出 Info 消息。
In my case, it happened when I was inflating several views from XML layout files programmatically. The message is harmless by itself, but could be the sign of a later problem that would use all the RAM your App is allowed to use and cause the mega-evil Force Close to happen. I have grown to be the kind of Developer that likes to see his Log WARN/INFO/ERROR Free. ;)
就我而言,它发生在我以编程方式从 XML 布局文件中扩充多个视图时。该消息本身是无害的,但可能是以后出现问题的迹象,该问题将使用您的应用允许使用的所有 RAM,并导致超级邪恶的 Force Close 发生。我已经成长为那种喜欢看到他的 Log WARN/INFO/ERROR Free 的开发人员。;)
So, this is my own experience:
所以,这是我自己的经验:
I got the message:
我收到消息:
10-09 01:25:08.373: I/Choreographer(11134): Skipped XXX frames! The application may be doing too much work on its main thread.
... when I was creating my own custom "super-complex multi-section list" by inflating a view from XML and populating its fields (images, text, etc...) with the data coming from the response of a REST/JSON web service (without paging capabilities) this views would act as rows, sub-section headers and section headers by adding all of them in the correct order to a LinearLayout (with vertical orientation inside a ScrollView). All of that to simulate a listView with clickable elements... but well, that's for another question.
...当我通过从 XML 扩展视图并使用来自 REST/ JSON web 服务(没有分页功能)这个视图将作为行、子节标题和节标题,通过将所有这些以正确的顺序添加到 LinearLayout(在 ScrollView 中具有垂直方向)。所有这些都是为了模拟带有可点击元素的 listView ......但是,这是另一个问题。
As a responsible Developer you want to make the App really efficient with the system resources, so the best practice for lists (when your lists are not so complex) is to use a ListActivity or ListFragment with a Loader and fill the ListView with an Adapter, this is supposedly more efficient, in fact it is and you should do it all the time, again... if your list is not so complex.
作为一个负责任的开发者,你想让应用程序真正有效地利用系统资源,所以列表的最佳实践(当你的列表不是那么复杂时)是使用带有加载器的 ListActivity 或 ListFragment 并用适配器填充 ListView,这应该是更有效的,事实上它是,你应该一直这样做,再次......如果你的清单不是那么复杂。
Solution: I implemented paging on my REST/JSON web service to prevent "big response sizes" and I wrapped the code that added the "rows", "section headers" and "sub-section headers" views on an AsyncTask to keep the Main Thread cool.
解决方案:我在我的 REST/JSON Web 服务上实现了分页以防止“大响应大小”,并且我包装了在 AsyncTask 上添加“行”、“节标题”和“子节标题”视图的代码以保持 Main线程很酷。
So... I hope my experience helps someone else that is cracking their heads open with this Info message.
所以......我希望我的经验可以帮助那些正在用这个信息消息打开他们的脑袋的人。
Happy hacking!
快乐黑客!
回答by Julien
In my case I have these messages when I show the sherlock action bar inderterminate progressbar. Since its not my library, I decided to hide the Choreographer outputs.
就我而言,当我显示 Sherlock 操作栏终止进度条时,我会收到这些消息。由于它不是我的图书馆,我决定隐藏 Choreographer 的输出。
You can hide the Choreographer outputs onto the Logcat view, using this filter expression :
您可以使用以下过滤器表达式将 Choreographer 输出隐藏到 Logcat 视图中:
tag:^((?!Choreographer).*)$
标签:^((?!编舞).*)$
I used a regex explained elsewhere : Regular expression to match a line that doesn't contain a word?
我使用了在别处解释的正则表达式: 正则表达式匹配不包含单词的行?
回答by Buzz
This usually happens when debugging using the emulator, which is known to be slow anyway.
这通常发生在使用模拟器进行调试时,众所周知,模拟器速度很慢。