该应用程序可能在其主线程上做过多的工作


379

我是Android SDK / API环境的新手。这是我第一次尝试绘制图表。我尝试使用3个不同的免费库运行仿真器的各种示例代码,但布局屏幕上没有任何显示。logcat重复以下消息:

 W / Trace(1378):nativeGetEnabledTags中的异常值:0
 I / Choreographer(1378):跳过了55帧!该应用程序可能在其主线程上做太多工作。

当我运行与许可库的评估副本有关的示例代码时,问题仍然存在,并且图表起作用了。


2
您是否在单独的线程上绘制图表?
Areks

感谢您的评论,我编辑了问题以使其更清楚。运行时的活动表明我正在运行的活动没有设计,其布局=>显示白色屏幕。
2013年

1
@Areks不,我没有使用单独的线程。
user2038135 2013年

1
我认为您根本不应该在主线程上执行长时间操作,因为这样会使整个应用程序冻结,您可以在此处阅读如何使用线程:stackoverflow.com/questions/3391272/… 忽略“执行代码” HTTP请求”,然后在那里执行您可能需要很长时间的操作。
Areks

1
为什么不尝试搜索,您会找到有关编舞者的信息。我建议你阅读这个答案:stackoverflow.com/questions/11266535/...
加布里埃尔埃斯特班

Answers:


479

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

任何开始开发android应用程序的人都会在logcat “ Choreographer(abc):跳过xx帧!该应用程序可能在其主线程上做过多的工作。” 因此,这实际上意味着什么,为什么要引起关注以及如何解决它。

这意味着您的代码需要花费很长时间进行处理,因此会跳过帧。这可能是因为您在应用程序或数据库访问的核心处进行了大量繁重的处理,或导致线程执行错误的任何其他操作停一会儿。

这是更详细的说明:

Choreographer允许应用程序将自身连接至vsync,并适当安排时间以提高性能。

Android视图动画在内部使用Choreographer来达到相同的目的:正确地设置动画时间并可能改善性能。

由于Choreographer被告知每个vsync事件,因此我可以判断Choreographer.post * api传递的Runnable之一是否在一帧时间内未完成,从而导致跳过帧。

以我的理解,编舞只能检测到跳帧。它无法说明为什么会这样。

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

来源: Logcat中编舞者消息的含义

为什么要担心

当此消息在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应用程序所需的知识,据我所知,每个初学者都会在他的控制台上收到此消息。


41
我只有一个应用程序,如果我单击某个按钮,则该按钮的背景图像会更改,并且该按钮不可单击。我怎么做太多工作:(
Remian8985

1
@ Remian8985-按钮的背景图像更改(假设您正在下载此图像)应该在AsyncTask中完成-即执行该下载背景操作并将结果发布到UI线程上(将图像提供回来)。请参阅Android参考链接
BenJaminSila 2016年

11
@BenJaminSila更改AsyncTask中的背景?真?
user25 2013年

11
@ user25 “假设您正在下载此图像”
forresthopkinsa

“当此消息在android模拟器上弹出,并且跳过的帧数非常小(<100)时,您可以安全地押注模拟器运行缓慢”今天是否仍然适用?模拟器变得越来越快了吧?
罗宾·迪克霍夫

243

正如其他人在上面回答的那样,“跳过了55帧!” 意味着您的应用程序正在处理一些繁重的工作。

就我而言,我的申请没有繁琐的过程。我对所有内容进行了两次和三次检查,并删除了我认为有些繁重的那些过程。

我删除了“片段”,“活动”和“库”,直到只剩下骨骼。但是问题仍然没有解决。我决定检查资源,发现我使用的一些图标和背景很大,因为我忘记了检查这些资源的大小。

因此,我的建议是,如果以上答案均无济于事,您还可以检查资源文件的大小。


1
也为我工作。我的应用程序工作量很少,但运行缓慢且缓慢。我一直在跳帧日志。从活动中删除背景后,一切都很好。谢谢!
akrabi

很好的答案,我相信这正是我的问题。我尝试了许多其他(相当多)的解决方案,而该应用程序的运行速度同样慢。我拿出所有Web服务,并尝试优化我的代码。没有用,然后我看到了。删除背景图片(我拥有的最大图片)后,即使使用旧的“慢速”代码,该应用也能以最快的速度单击内容。
M Barbosa

你让我今天一整天都感觉很好!
Nicolas Mastromarino

:)你是个天才的天才。
梅丁·伊尔汗

@batsheva不必为1 KB。这取决于您的需求,例如您需要更清晰的图像,可以使用更高的分辨率,但请确保将大小分成不同的资源文件夹。
锡胡

61

我也有同样的问题。
我的情况是我正在使用可绘制的背景图像。该特定图像约为130kB,并在我的android应用程序的启动屏幕和主页中使用。

解决方案 -我只是将特定图像从可绘制对象移到了drawables-xxx文件夹,并且可以释放大量在后台占用的内存,并且跳过的帧不再被跳过。

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


7
我将我的大背景图像从可绘制图像移到了mimap-xxxhdpi,它成功了!
bgplaya

你帮了很多忙 谢谢
N.Droid '17

2
此解决方案可以解决问题。我使用的文件夹drawable-xxxhdpi,而不是drawable什么大大减少了使用的内存(小于〜70%)。同样要知道的是,相同尺寸的屏幕的DPI尺寸也有所不同。在它们之间的像素的比例是ldpi = 1:0.75mdpi = 1:1hdpi = 1:1.5xhdpi = 1:2xxhdpi = 1:3xxxhdpi = 1:4。通过使用该drawable-xxxhdpi文件夹,您可以将图像缩小到设备的屏幕尺寸,从而减少内存和CPU消耗。
TimoBähr17年

2
将图像从drawable移到会drawable-nodpi阻止应用程序获取Out of Memory Error
Shruti

哦,天哪...谢谢!我在drawable文件夹中有一个图像,这使我的应用程序变慢了(尽管图像只有100kb !!!)。生成drawable-xxx文件(我使用Android Drawable Importer)后,我的应用程序运行速度很快。非常感谢!
错误1337年

20

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

解决此问题的一种好方法是从后台线程中首先触发SharedPreference加载,该加载应尽早开始(例如,从onCreateApplication类的加载)。这样,首选项对象可能已经在您要使用它的时候构建了。

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


1
对于这种情况,您应该首选apply()方法而不是commit()。apply()方法不能阻止UI。您可以从此处查看developer.android.com/training/data-storage/shared-preferences
EmreGürses,

16

尝试使用以下策略来提高您的应用程序性能:

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

3
您的第一个链接要求您“ ...拥有一个经过验证的帐户...”才能访问它。
chornge

9

我有同样的问题。Android Emulator在Android <6.0上完美运行。当我使用模拟器Nexus 5(Android 6.0)时,该应用程序I/Choreographer: Skipped frames在日志中的运行速度非常慢。

因此,我通过更改清单文件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>

8

我不是专家,但是当我想将数据从我的Android应用程序发送到Web服务器时,却收到了此调试消息。尽管我使用了AsyncTask类并在后台进行了数据传输,但为了从服务器获取结果数据,我使用了AsyncTask类的get()方法,该方法使UI同步,这意味着您的UI将等待太长时间。因此,我的建议是让您的应用在单独的线程上执行所有面向网络的任务。


6

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


4
通过Java代码或使用Photoshop减少图像大小来裁剪图像..也使用Compressor.io压缩图像
HarshitG

5

我有同样的问题。在我的情况下,我有2个嵌套的相对布局。RelativeLayout始终必须执行两次度量传递。如果嵌套RelativeLayouts,则会得到指数测量算法。


4

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


1

我有同样的问题。当我在另一台计算机上运行代码时,它运行良好。但是,在我的系统上,它显示“应用程序可能在其主线程上做太多工作”。

我通过重新启动Android Studio解决了我的问题[文件->无效的缓存/重新启动->单击“无效并重新启动”]。


我不知道您的解决方案为何有效。无论如何,谢谢。
Bhuvanesh BS

1

就我而言,这是因为我不小心在方法上设置了一个断点。一旦清除它,消息消失了,性能大大提高了。


0

我的应用有同样的问题。但是除了显示卡片列表和文本之外,它没有做其他事情。什么都没有在后台运行。但是,经过一番调查后,发现卡背景的图像集引起了这种情况,即使它很小(350kb)。然后,我使用http://romannurik.github.io/AndroidAssetStudio/index.html将图像转换为9patch图像 。
这对我有用。


0

在这个问题上做了很多研发之后,我得到了解决方案,

以我为例,我使用的Service将每2秒运行一次,并且使用runonUIThread,我想知道问题在那里但根本没有。我发现的下一个问题是,我可能在May App中使用大图像,这就是问题所在。

我删除了图像并设置了新图像。

结论:-查看您的代码,您使用的原始文件是否很大。


0

首先阅读警告。它表示主线程上有更多负载。因此,您要做的就是在线程中运行具有更多工作的功能。


-1

在开发在网格布局上使用大量可绘制png文件的应用程序时遇到了同样的问题。我还尝试了尽可能优化我的代码..但是它对我没有用。可绘制资源的大小(如果有)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.