Logcat的编舞信息的意义
我安装了最新版本的SDK (API 16)
并获得了最新的ADT。 我现在看到这些消息在logcat,我很确定,我以前没有见过。 有没有人有这个想法?
06-29 23:11:17.796:我/编舞(691):跳过647帧! 应用程序可能在其主线程上做了太多的工作。
我做了一个search,并find这个链接: http : //developer.android.com/reference/android/view/Choreographer.html 。 这是API 16中引入的新类。
我需要知道如何才能确定我的应用程序可能做的“太多工作”,因为我所有的处理都是在AsyncTask
完成的。
编排器允许应用程序将自己连接到vsync,并适当地设置时间以提高性能。
Android视图animation在内部使用Choreographer来达到相同的目的:适当的时间animation并可能提高性能。
由于Choreographer被告知关于每个vsync事件,我可以判断一个帧是否被一个帧时间完成,是否有一个Runnables被Choreographer.post * apis传递,导致帧被跳过。
在我的理解编舞只能检测跳帧。 没有办法解释为什么会发生这种情况。
消息“应用程序可能在其主线程上做了太多工作”。 可能会引起误解。
我迟到了,但希望这是一个有益的补充,在这里的其他答案…
回答问题/ tl:dr;
我需要知道如何才能确定我的应用程序可能正在做什么“太多的工作”,因为我的所有处理都是在AsyncTasks中完成的。
以下是所有候选人:
- 主线程上的IO或昂贵的处理(加载drawables,膨胀布局以及在
ImageView
上设置Uri
都在主线程上构成IO) - 渲染大型/复杂/深层
View
层次结构 - 使
View
层次结构的大部分失效 - 在自定义
View
昂贵的onDraw
方法 - 昂贵的animation计算
- 运行“worker”线程的优先级过高,被认为是“背景”(
AsyncTask
默认是“background”,java.lang.Thread
不是 ) - 生成大量的垃圾,导致垃圾收集器“停止世界” – 包括主线程 – 清理
要真正确定具体原因,您需要对应用进行configuration。
更多详情
我一直试图通过试验和看代码来了解编舞。
Choreographer的文档以“协调animation,input和绘图的时间”开始。 这实际上是一个很好的描述,但是其余的过分强调animation。
编排器实际上负责执行3种types的callback,它们按以下顺序运行:
- input处理callback(处理用户input,如触摸事件)
- 在帧之间进行补间的animationcallback,为正在运行的任何/全部animation提供稳定的帧开始时间。 运行这些callback第二意味着任何animation相关的计算(例如,视图的更改位置)已经在第三种callback被调用时进行了…
- 查看遍历callback以绘制视图层次结构。
目标是匹配无效视图重新绘制(和animation补间)的速度与屏幕vsync – 通常60fps。
关于跳过的帧的警告看起来像是一个事后的想法:如果通过3个步骤的单次传输超过了预期的帧持续时间的30倍,则会logging该消息,因此您希望在日志消息中看到的最小数量是“跳过30帧” ; 如果每次通过的时间超过了50%,你仍然会跳过30帧( 淘气! ),但是你不会被警告。
从3个步骤中清楚地知道,不仅可以触发警告的animation:使大型View
层次结构的重要部分失效或具有复杂的onDraw方法的View
失效可能就足够了。
例如,这将会反复触发警告:
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) {} } }); } }
…这样产生日志logging:
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
中看到编排器是否参与,无论你是否在animation:
AnanoyTheChoreographerActivity $ 1.onDraw(AnnoyTheChoreographerActivity.java:25)at android.view.View.draw(View.java:13759)
相当多的重复…
在android.widget的android.view.View.draw(View.java:13762)的android.view.ViewGroup.dispatchDraw(ViewGroup.java:3039)处的android.view.ViewGroup.drawChild(ViewGroup.java:3169)。 FrameLayout.draw(FrameLayout.java:467)at com.android.internal.policy.impl.PhoneWindow $ DecorView.draw(PhoneWindow.java:2396)at android.view.ViewDisplayList(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。在android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1112)在android.view.ViewRootImpl $ TraversalRunnable.run android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1956)ViewRootImpl.performDraw(ViewRootImpl.java:2145) (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(Cho android.view.Choreographer $ FrameDisplayEventReceiver.run(Choreographer.java:711) at android.os.Handler.handleCallback(Handler.java:615)at android.os.Handler.dispatchMessage(Handler.java :92)在android.app.ActivityThread.main(ActivityThread.java:4898)android.os.Looper.loop(Looper.java:137)
最后,如果来自其他线程的争用减less了主线程的工作量,那么即使你并没有在主线程中进行实际的工作,跳帧的机会也会大大增加。
在这种情况下,build议应用程序在主线程上做的太多,可能会被误认为是错误的,但是Android真的希望工作线程以低优先级运行,以防止主线程被饿死。 如果你的工作线程是低优先级的,触发编排器警告的唯一方法就是在主线程上做太多事情。
如果在很多情况下可能会在您的LogCat中popup信息消息。
就我而言,当我以编程方式从XML布局文件膨胀几个视图时,就发生了这种情况。 该信息本身是无害的,但可能是后来的问题的标志,将使用您的应用程序允许使用的所有内存,并导致巨型邪恶力量closures发生。 我已经成长为那种喜欢看到他的日志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.
…当我创build自己的定制的“超复杂的多节列表”时,通过从XML扩展视图并填充其字段(图像,文本等)与来自REST / JSON Web服务(没有分页function)这个视图将作为行,子节头和节标题通过将所有这些按照正确的顺序添加到LinearLayout(在ScrollView中具有垂直方向)。 所有这些都是为了模拟带有可点击元素的列表视图…但是,这是另一个问题。
作为一个负责任的开发人员,您希望使系统资源真正高效,因此列表的最佳实践(当列表不那么复杂时)是使用ListActivity或ListFragment和Loader,并将ListView填充为Adapter,这应该是更有效率,事实上,这是,你应该一直这样做,如果你的名单不是那么复杂。
解决scheme:我在REST / JSON Web服务上实现了分页,以防止“很大的响应大小”,并且在AsyncTask中包含了添加“行”,“节头”和“子节头”视图的代码,以保持主线程很酷。
所以…我希望我的经验可以帮助那些正在打开信息的人开放。
快乐的黑客!
这通常发生在使用模拟器进行debugging时,无论如何,这个模拟器已经很慢了。
在我的情况下,当我显示sherlock操作栏inderterminate进度栏时,我有这些消息。 既然不是我的图书馆,我决定隐藏编舞者的输出。
您可以使用以下filterexpression式将编排器输出隐藏到Logcat视图中:
标签:^((?!编舞)。*)$
我用了一个正则expression式解释其他地方: 正则expression式匹配一个不包含单词的行吗?
- 在ListView中为ListActivity在AbsListView.obtainView中崩溃
- ProgressDialog:如何防止泄漏的窗口
- intent.setType(type)可能的意图types是什么?
- getContext(),getApplicationContext(),getBaseContext()和“this”
- 如何使用vector绘图与除了ImageView与srcCompat?
- Android:更改button文字和背景颜色
- java.lang.ClassCastException:android.view.ViewGroup $ LayoutParams不能转换为android.widget.Gallery $ LayoutParams
- 如何在popup窗口中显示input错误?
- 如何在ViewPager上进行循环滚动?