应用程序可能在其主线程上做了太多工作

use*_*135 354 multithreading android

我是Android SDK/API环境的新手.这是我第一次尝试绘制情节/图表.我尝试使用3个不同的免费库运行不同类型的示例代码模拟器,在布局屏幕中没有显示任何内容.logcat重复以下消息:

 W/Trace(1378): Unexpected value from nativeGetEnabledTags: 0
 I/Choreographer(1378): Skipped 55 frames!  The application may be doing too much work on its main thread. 

当我运行与许可库的评估副本有关的示例代码时,问题不会持续存在并且图表有效.

Jor*_*sys 452

取自:Android UI:修复跳过的帧

任何开始开发Android应用程序的人都会在logcat上看到这条消息"Choreographer(abc):Skipped xx frames!应用程序可能在其主线程上做了太多工作."那么它实际意味着什么,为什么要关注它以及如何解决它.

这意味着您的代码需要很长时间才能处理,并且因为它而跳过了框架,这可能是因为您在应用程序或数据库访问的核心进行了一些繁重的处理,或导致该线程的任何其他因素停一会儿.这是一个更详细的解释:

编排器允许应用程序将自己连接到vsync,并正确地计时以提高性能.

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

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

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

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

source: Logcat中Choreographer消息的含义

为什么你应该担心

当这个消息在Android模拟器上弹出并且跳过的帧数相当小(<100)时,你可以安全地下注模拟器很慢 - 几乎所有时间都会发生这种情况.但是如果帧数跳过而且大而且大约为300+,则代码可能会出现严重问题.与ios和Windows设备不同,Android设备有大量硬件.RAM和CPU各不相同,如果您想在所有设备上获得合理的性能和用户体验,那么您需要解决这个问题.当跳过帧时,UI缓慢且滞后,这不是理想的用户体验.

如何解决它

解决这个问题需要识别可能发生或可能发生长时间处理的节点.最好的方法是进行所有处理,无论与主UI线程分开的线程有多小或多大.因此,它可以从SQLite数据库访问数据或进行一些核心数学或简单地对数组进行排序 - 在不同的线程中进行

现在有一个问题,你将创建一个新的线程来执行这些操作,当你运行你的应用程序时,它会崩溃说"只有创建视图层次结构的原始线程才能触及它的视图".你需要知道这个事实,android中的UI只能由主线程或UI线程更改.尝试这样做的任何其他线程都会因此错误而失败并崩溃.你需要做的是在runOnUiThread中创建一个新的Runnable,在这个runnable中你应该做所有涉及UI的操作.在这里找一个例子.

所以我们有Thread和Runnable来处理主线程的数据,还有什么?android中有AsyncTask,可以在UI线程上进行长时间的处理.当您的应用程序是数据驱动或Web api驱动或使用复杂的UI(如使用Canvas构建的UI)时,这是最有用的.AsyncTask的强大功能是允许在后台执行操作,一旦完成处理,您只需在UI上执行所需的操作,而不会产生任何滞后效应.这是可能的,因为AsyncTask从Activity的UI线程派生自己 - 通过AsyncTask在UI上执行的所有操作都是与主UI线程不同的线程,不妨碍用户交互.

所以这是你需要知道的平滑的Android应用程序,并且据我所知,每个初学者都在他的控制台上获取此消息.

  • 我只是有一个应用程序,如果我点击一个按钮,按钮的背景图像更改,按钮是不可点击的.我怎么做太多的工作:( (28认同)
  • @BenJaminSila改变了AsyncTask的背景?真? (8认同)
  • @ user25*"假设您正在下载此图片"* (8认同)
  • “当此消息在 android 模拟器上弹出并且跳过的帧数相当小(&lt;100)时,您可以安全地打赌模拟器很慢”这在今天仍然适用吗?模拟器越来越快了吧? (4认同)
  • AsyncTask 现已弃用! (2认同)

Sit*_*thu 225

正如其他人在上面回答的那样,"跳过了55帧!" 意味着你的申请中有一些繁重的处理.

就我而言,我的申请中没有繁重的过程.我对所有内容进行了双倍和三重检查,并删除了我认为有点沉重的过程.

我删除了碎片,活动,库,直到只剩下骨架.但问题仍然没有消失.我决定检查资源,发现我使用的一些图标和背景非常大,因为我忘了检查这些资源的大小.

所以,我的建议是,如果上述答案都没有帮助,您也可以检查资源文件的大小.

  • 也为我工作过。我有一个应用程序只做很少的工作,但速度缓慢且滞后。我不断收到跳帧日志。一旦我从我的活动中删除背景,一切都很好。谢谢! (4认同)

Pra*_*tha 59

我也有同样的问题.
我的情况是我在使用可绘制的背景图像.这个特定的图像大约130kB,并在我的Android应用程序中的启动画面和主页使用.

解决方案 - 我只是将该特定图像从drawables转移到drawables-xxx文件夹,并且可以释放大量内存占用的背景,并且不再跳过跳帧.

更新使用'nodp'可绘制资源文件夹存储背景drawables文件.
密度合格的可绘制文件夹或drawable-nodpi是否优先?

  • 我将我的大背景图像从drawable移动到mimap-xxxhdpi,它就完成了! (6认同)
  • 这个解决方案正在诀窍.我使用文件夹`drawable-xxxhdpi`而不是'drawable`,这大大减少了使用的内存(减少了约70%).另外要知道的是,相同尺寸的屏幕的DPI尺寸也各不相同.它们之间的像素比例是`ldpi = 1:0.75`,`mdpi = 1:1`,`hdpi = 1:1.5`,`xhdpi = 1:2`,`xxhdpi = 1:3`,`xxxhdpi = 1:4`.通过使用`drawable-xxxhdpi`文件夹,您可以将图像缩小到设备的屏幕尺寸,从而减少内存和CPU消耗. (2认同)
  • 将图像从“drawable”移动到“drawable-nodpi”可防止应用程序出现“内存不足错误”。 (2认同)

use*_*723 18

UI线程延迟的另一个常见原因是SharedPreferences访问.当您PreferenceManager.getSharedPreferences第一次调用其他类似方法时,会立即加载相关的.xml文件并在同一个线程中进行解析.

解决此问题的一个好方法是从后台线程触发第一个SharedPreference加载,尽可能早地启动(例如从onCreate您的Application类开始).这样,首选对象可能已经在您想要使用它时构建.

不幸的是,有时在启动的早期阶段(例如在初始Activity或甚至应用程序本身)中读取首选项文件是必要的.在这种情况下,仍然可以通过使用来避免停止UI MessageQueue.IdleHandler.在主线程上执行您需要执行的所有其他操作,然后安装IdleHandler以在完全绘制Activity后执行代码.在该Runnable中,您应该能够访问SharedPreferences而不会延迟太多的绘图操作并使Choreographer不满意.

  • 对于这种情况,您应该更喜欢 apply() 方法而不是 commit()。apply() 方法不能阻塞 UI。您可以从这里查看https://developer.android.com/training/data-storage/shared-preferences (2认同)

Mig*_*Dus 16

尝试使用以下策略以提高应用性能:

  • 如果可能,请使用多线程编程.即使您的智能手机有一个核心(线程可以在不同的核心运行,如果处理器有两个或更多),性能优势也是巨大的.使您的应用程序逻辑与UI分离很有用.使用Java线程,AsyncTask或IntentService.检查一下.
  • 阅读并遵循Android开发网站的misc性能提示.这里检查.

  • 您的第一个链接要求您“ ...拥有一个经过验证的帐户...”才能访问它。 (2认同)

phe*_*non 9

我有同样的问题.Android Emulator在Android <6.0上完美运行.当我使用模拟器Nexus 5(Android 6.0)时,应用程序I/Choreographer: Skipped frames在日志中工作得很慢.

所以,我通过更改Manifest文件hardwareAccelerated选项来解决这个问题,true如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application android:hardwareAccelerated="true">
        ...
    </application>
</manifest>
Run Code Online (Sandbox Code Playgroud)

  • 对于那些将来阅读本文的人来说,这是不必要的。如果您的目标 API 级别高于 14,则默认启用硬件加速。根据文档。“如果您的目标 API 级别 &gt;=14,则默认启用硬件加速,但也可以显式启用。” 来源:https://developer.android.com/guide/topics/graphics/hardware-accel (4认同)

小智 7

我不是专家,但是当我想将数据从我的Android应用程序发送到Web服务器时,我得到了这个调试消息.虽然我使用了AsyncTask类并在后台进行了数据传输,但是为了从服务器获取结果数据,我使用了AsyncTask类的get()方法,这使得UI同步,这意味着你的UI将等待太长时间.所以我的建议是让你的应用程序在一个单独的线程上完成每个面向网络的任务.


Hos*_*ami 6

这通常发生在您在主线程中执行大型进程时。跳过小于 200 的帧是可以的。但是如果跳过的帧超过 200,它会减慢应用程序 UI 线程的速度。您可以做的是在一个称为工作线程的新线程中执行这些过程,之后,当您想访问并使用 UI 线程执行某些操作时(例如:使用视图、findView 等执行某些操作...),您可以使用处理程序或runOnUiThread(我更喜欢这个)以显示处理结果。这绝对解决了问题。使用工作线程非常有用,甚至在这种情况下必须使用。


Rad*_*lav 5

我有同样的问题.在我的情况下,我有2个嵌套的相对布局.RelativeLayout总是要做两次测量.如果嵌套RelativeLayouts,则会得到指数测量算法.


Har*_*itG 5

优化图像...不要使用大于100KB的图像...图像加载会占用过多的CPU并导致应用程序挂起。

  • 通过Java代码或使用Photoshop减少图像大小来裁剪图像..也使用Compressor.io压缩图像 (3认同)

归档时间:

查看次数:

365700 次

最近记录:

5 年,9 月 前