Logcat中Choreographer消息的含义

时间:2012-06-29 17:44:35

标签: android android-logcat

我安装了最新版本的SDK (API 16)并获得了最新的ADT。我现在在logcat中看到这些消息,我很确定,我以前没见过。有没有人对此有所了解?

  

06-29 23:11:17.796:I / Choreographer(691):跳过647帧!该   应用程序可能在其主线程上做了太多工作。

我进行了搜索并找到了这个链接: http://developer.android.com/reference/android/view/Choreographer.html。这是API 16中引入的新类。

我需要知道如何确定我的应用程序可能做的“太多工作”,因为我的所有处理工作都在AsyncTask完成。

5 个答案:

答案 0 :(得分:132)

Choreographer允许应用程序将自己连接到vsync,并正确计时以提高性能。

Android视图动画在内部使用Choreographer用于同一目的:正确计时动画并可能提高性能。

由于Choreographer被告知每个vsync事件,我可以判断Choreographer.post * apis传递的其中一个Runnables是否在一帧的时间内完成,导致跳过帧。

在我的理解中,编舞者只能检测跳帧。它无法解释为什么会发生这种情况。

消息“应用程序可能在其主线程上做了太多工作。”可能会产生误导。

答案 1 :(得分:64)

我已经迟到了,但希望这是对其他答案的有用补充......

回答问题/ tl:dr;

  

我需要知道如何确定"过多的工作"我的应用程序可能正在执行,因为我的所有处理都是在AsyncTasks中完成的。

以下是所有候选人:

  • 主线程上的IO或昂贵的处理(在Uri上加载drawable,膨胀布局和设置ImageView都构成主线程上的IO) / LI>
  • 渲染大型/复杂/深层View层次结构
  • 使View层次结构的大部分无效
  • 自定义onDraw&#39>中的昂贵View方法
  • 动画中的昂贵计算
  • 跑步"工人"线程太高优先考虑"背景" (AsyncTask"背景"默认情况下,java.lang.Thread
  • 产生大量垃圾,导致垃圾收集器停止世界" - 包括主线程 - 在清理时

实际确定您需要对应用进行个人资料的具体原因。

更多详情

我一直试图通过试验和查看code来了解编舞。

Choreographer的文档打开时使用"协调动画,输入和绘图的时间。"这实际上是一个很好的描述,但其余的继续过分强调动画。

Choreographer实际上负责执行3种类型的回调,它们按以下顺序运行:

  1. 输入处理回调(处理用户输入,如触摸事件)
  2. 动画回调帧之间的补间,为正在运行的任何/所有动画提供稳定的帧启动时间。运行这些回调第二意味着在调用第三种类型的回调时已经进行了任何与动画相关的计算(例如,改变了View的位置)......
  3. 查看用于绘制视图层次结构的遍历回调。
  4. 目的是将重新绘制无效视图(和补间动画)的速率与屏幕vsync相匹配 - 通常为60fps。

    关于跳过帧的警告看起来像是事后的想法:如果单个通过3个步骤所需的帧时间超过30倍,则会记录该消息,因此您可以预期看到的最小数字在日志消息中"跳过 30 帧&#34 ;;如果每个传递的时间比它应该延长50%,你仍然会跳过30帧(顽皮!),但你不会被警告。

    从所涉及的3个步骤可以清楚地看出,它不仅仅是可以触发警告的动画:使用复杂的onDraw方法使大View层次结构的重要部分或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) {}
                }
            });
        }
    }
    

    ...产生这样的记录:

    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期间从堆栈中看到编舞者是否参与,无论你是否在制作动画:

      

    at 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)   在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:1112)   在android.view.ViewRootImpl $ TraversalRunnable.run(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)   在android.os.Handler.handleCallback(Handler.java:615)   在android.os.Handler.dispatchMessage(Handler.java:92)   在android.os.Looper.loop(Looper.java:137)   在android.app.ActivityThread.main(ActivityThread.java:4898)

    最后,如果来自其他线程的争用减少了主线程可以完成的工作量,即使您没有在主线程上进行工作,跳帧的可能性也会大大增加。

    在这种情况下,建议应用程序在主线程上执行过多操作可能会被误导,但Android really wants worker threads to run at low priority可能会阻止它们使主线程挨饿。如果你的工作线程是低优先级,那么触发Choreographer警告的唯一方法就是在主线程上做太多。

答案 2 :(得分:24)

如果在很多情况下可能会在LogCat中弹出一条信息消息。

就我而言,当我以编程方式从XML布局文件中膨胀多个视图时,就发生了这种情况。这条消息本身是无害的,但可能是后来问题的标志,它将使用你的应用程序允许使用的所有RAM,并导致巨大的邪恶力量关闭发生。我已经成长为喜欢看他的Log 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 Web服务(没有分页功能)通过将所有这些视图以正确的顺序添加到LinearLayout(在ScrollView中具有垂直方向),这些视图将充当行,子节标题和节标题。所有这些都是为了模拟带有可点击元素的listView ......但是,这是另一个问题。

作为一个负责任的开发人员,您希望使用系统资源使应用程序真正高效,因此列表的最佳实践(当您的列表不那么复杂时)是使用带有Loader的ListActivity或ListFragment并填充ListView一个适配器,这应该更高效,事实上它是,你应该一直这样做,再次...如果你的列表不是那么复杂。

解决方案:我在我的REST / JSON Web服务上实现了分页,以防止“大响应大小”,并且我在AsyncTask上包含了添加“rows”,“section headers”和“sub-section headers”视图的代码保持主线冷却。

所以...我希望我的经验可以帮助其他人用这条信息消息打开他们的头脑。

快乐的黑客攻击!

答案 3 :(得分:11)

这通常在使用模拟器进行调试时发生,而模拟器无论如何都是慢速的。

答案 4 :(得分:11)

在我的情况下,当我显示sherlock操作栏不确定进度条时,我有这些消息。由于它不是我的图书馆,我决定隐藏编舞者的作品。

您可以使用此过滤器表达式将Choreographer输出隐藏到Logcat视图中:

代码:^((?编导)。*)$

我使用了其他地方解释的正则表达式:Regular expression to match a line that doesn't contain a word?