应用程序可能在其主线程上做了太多工作
Posted
技术标签:
【中文标题】应用程序可能在其主线程上做了太多工作【英文标题】:The application may be doing too much work on its main thread 【发布时间】:2013-01-18 16:07:12 【问题描述】:我是 android SDK/API 环境的新手。这是我第一次尝试绘制绘图/图表。我尝试使用 3 个不同的免费库在模拟器上运行不同类型的示例代码,但布局屏幕上没有显示任何内容。 logcat 正在重复以下消息:
W/Trace(1378):来自 nativeGetEnabledTags 的意外值:0 I/Choreographer(1378):跳过了 55 帧!。当我运行与许可库的评估副本有关的示例代码时,问题并没有持续存在,并且图表工作正常。
【问题讨论】:
您是在单独的线程上绘制图表吗? 感谢您的评论,我编辑了问题以使其更清楚。运行时的活动显示我正在运行一个没有设计布局的活动=>显示白屏。 @Areks 不,我没有使用单独的线程。 我认为你应该,完全不建议在主线程上执行长时间操作,因为这会冻结整个应用程序,你可以在这里阅读如何使用线程:***.com/questions/3391272/…忽略“代码执行 HTTP 请求”并在那里执行您可能需要很长时间的操作。 为什么不尝试搜索,您会找到有关编舞的信息。我建议您阅读此答案:***.com/questions/11266535/… 【参考方案1】:取自:Android UI : Fixing skipped frames
任何开始开发 android 应用程序的人都会在 logcat “编舞(abc):跳过xx帧!该应用程序可能是 在它的主线程上做了太多的工作。” 那么它实际上是做什么的 意思是,你为什么要担心以及如何解决它。
这意味着您的代码需要很长时间来处理和帧 因为它而被跳过,可能是因为一些沉重的 您在应用程序或数据库的核心进行的处理 访问或任何其他导致线程停止一段时间的事情。
这里有更详细的解释:
Choreographer 允许应用将自己连接到 vsync,并且 适当安排时间以提高性能。
Android 视图动画在内部使用 Choreographer 来实现相同的功能 目的:正确计时动画并可能改进 性能。
由于 Choreographer 被告知每个 vsync 事件,我可以判断是否 Choreographer.post* api 传递的 Runnable 之一 没有在一帧的时间内完成,导致帧被跳过。
据我了解,Choreographer 只能检测到跳帧。 它无法说明为什么会发生这种情况。
消息“应用程序可能在其主 线。”可能会产生误导。
来源: Meaning of Choreographer messages in Logcat
为什么要担心
当此消息在 android 上弹出时 模拟器和跳过的帧数相当小(
如何解决
解决此问题需要识别存在或 可能会发生长时间的处理。最好的方法是做 所有的处理,不管线程中的大小是分开的 从主 UI 线程。所以无论是从 SQLite 数据库访问数据还是 做一些核心数学或简单地对数组进行排序——在一个 不同的线程
现在这里有一个问题,你将创建一个新线程来做 这些操作,当你运行你的应用程序时,它会崩溃 说“只有创建视图层次结构的原始线程才能 触摸它的观点”。你需要知道这个事实,android 中的 UI 可以 仅由主线程或 UI 线程更改。任何其他线程 尝试这样做,失败并崩溃并出现此错误。你什么 需要做的是在runOnUiThread和里面创建一个新的Runnable 这个runnable你应该做所有涉及UI的操作。找 一个例子here。
所以我们有 Thread 和 Runnable 用于处理主线程之外的数据, 还有什么? android中有AsyncTask可以做很长时间 UI线程上的进程。这是最有用的,当你 应用程序是数据驱动的或 Web api 驱动的或使用复杂的 UI 就像那些使用 Canvas 构建的。 AsyncTask 的强大之处在于 允许在后台做事,一旦你完成了 处理,您可以简单地在 UI 上执行所需的操作,而无需 造成任何滞后效应。这是可能的,因为 AsyncTask 派生自 Activity 的 UI 线程——你所做的所有操作 通过 AsyncTask 在 UI 上完成是与主 UI 不同的线程 线程,不妨碍用户交互。
所以这是你制作流畅的android需要知道的 应用程序,据我所知,每个初学者都会在他的 控制台。
【讨论】:
我只有一个应用程序,如果我点击一个按钮,按钮的背景图像会发生变化,并且按钮是不可点击的。我怎么做的工作太多了:( @BenJaminSila 在 AsyncTask 中更改背景?真的吗? @user25 "假设你正在下载这张图片" “当这个消息在 android 模拟器上弹出并且跳过的帧数相当少( AsyncTask 现已弃用!【参考方案2】:正如其他人在上面回答的那样,“跳过了 55 帧!”意味着您的应用程序中有一些繁重的处理。
就我而言,我的申请中没有繁重的流程。我仔细检查了所有内容并删除了那些我认为有点繁重的过程。
我删除了 Fragments、Activity、Libraries,直到只剩下骨架。但问题仍然没有消失。我决定检查资源,发现我使用的一些图标和背景非常大,因为我忘记检查这些资源的大小。
所以,我的建议是,如果以上答案都没有帮助,您还可以检查您的资源文件大小。
【讨论】:
也为我工作。我有一个应用程序做的工作很少,但又慢又迟钝。我不断收到跳帧日志。一旦我从我的活动中删除了背景,一切都很好。谢谢! 很好的答案,我相信这正是我的问题。我尝试了一堆其他(相当复杂的)解决方案,应用程序同样慢。我拿出了所有的网络服务,并试图优化我的代码。没有工作,然后我看到了这个。一旦我删除了我的背景图片(我拥有的最大图片),该应用程序的运行速度与您点击内容一样快,即使使用旧的“慢”代码也是如此。 你成就了我的一天! :) 你是个绝对的天才。 @batsheva 不必为 1 KB。这取决于您的需求,假设您需要更清晰的图像,您可以使用更高的分辨率,但请确保您将资源分成不同的大小到不同的文件夹中。【参考方案3】:我也有同样的问题。 我的情况是,我使用的是可绘制对象中的背景图像。该特定图像约为 130kB,并在我的 Android 应用程序的初始屏幕和主页期间使用。
解决方案 - 我刚刚将该特定图像从 drawables 转移到 drawables-xxx 文件夹,并且能够释放后台占用的大量内存,并且跳过的帧不再跳过。
更新使用“nodp”可绘制资源文件夹来存储背景可绘制对象 文件。 Will a density qualified drawable folder or drawable-nodpi take precedence?
【讨论】:
我把我的大背景图片从 drawable 移到了 mimap-xxxhdpi,它成功了! 你帮了很多忙。谢谢 这个解决方案可以解决问题。我正在使用文件夹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 消耗。
将图像从drawable
移动到drawable-nodpi
会阻止应用程序获取Out of Memory Error
。
天哪……谢谢!我在可绘制文件夹中有一张图片,这让我的应用程序慢得要命(尽管图片只有 100kb !!!)。生成 drawable-xxx 文件后(我使用了 Android Drawable Importer),我的应用程序非常快。非常感谢!【参考方案4】:
另一个导致 UI 线程延迟的常见原因是 SharedPreferences 访问。当您第一次调用PreferenceManager.getSharedPreferences
和其他类似方法时,关联的.xml 文件会立即在同一线程中加载和解析。
解决此问题的一个好方法是从后台线程触发第一个 SharedPreference 加载,尽早启动(例如,从 Application 类的 onCreate
开始)。这样,偏好对象可能在您想要使用它的时候就已经构建好了。
不幸的是,有时在启动的早期阶段(例如在初始 Activity 甚至应用程序本身)读取首选项文件是必要的。在这种情况下,仍然可以通过使用MessageQueue.IdleHandler
来避免 UI 停滞。在主线程上执行您需要执行的所有其他操作,然后在您的 Activity 完全绘制后安装 IdleHandler 以执行代码。在该 Runnable 中,您应该能够访问 SharedPreferences 而不会延迟太多绘图操作并使 Choreographer 不高兴。
【讨论】:
对于这种情况,您应该更喜欢 apply() 方法而不是 commit()。 apply() 方法不能阻塞 UI。你可以从这里看developer.android.com/training/data-storage/shared-preferences【参考方案5】:尝试使用以下策略来提高您的应用性能:
尽可能使用多线程编程。即使您的智能手机只有一个内核(如果处理器有两个或更多,线程可以在不同的内核中运行),性能优势也是巨大的。使您的应用程序逻辑与 UI 分离很有用。使用 Java 线程、AsyncTask 或 IntentService。 Check this。 阅读并遵循 Android 开发网站的 misc 性能提示。 Check here。【讨论】:
您的第一个链接要求您“...拥有经过验证的帐户...”才能访问它。【参考方案6】:我遇到了同样的问题。 Android Emulator 在 Android 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>
【讨论】:
【参考方案7】:我不是专家,但是当我想将数据从我的 android 应用程序发送到 Web 服务器时,我收到了这条调试消息。虽然我使用了 AsyncTask 类并在后台进行数据传输,但为了从服务器获取结果数据,我使用了 AsyncTask 类的 get() 方法,这使得 UI 同步,这意味着你的 UI 将等待太久。所以我的建议是让你的应用在一个单独的线程上完成所有面向网络的任务。
【讨论】:
【参考方案8】:我遇到了同样的问题。就我而言,我有 2 个嵌套的相对布局。 RelativeLayout 总是必须进行两次测量传递。如果嵌套 RelativeLayouts,就会得到指数测量算法。
【讨论】:
【参考方案9】:优化您的图片...不要使用大于 100KB 的图片...图片加载占用过多 CPU 并导致您的应用挂起。
【讨论】:
通过 java 代码或使用 Photoshop 裁剪图像来减小图像大小.. 也可以使用compressor.io 压缩图像【参考方案10】:这通常发生在您在主线程中执行大型进程时。跳过少于 200 的帧是可以的。但是如果跳过的帧超过 200,它会减慢应用程序 UI 线程的速度。您可以做的是在一个称为工作线程的新线程中执行这些过程,然后,当您想要访问并使用 UI 线程执行某些操作(例如:使用视图、findView 等执行某些操作)时,您可以使用 handler 或 runOnUiThread(我更喜欢这个),以便显示处理结果。 这绝对解决了问题。在这种情况下,使用工作线程非常有用,甚至必须使用。
【讨论】:
【参考方案11】:我遇到了同样的问题。当我在另一台计算机上运行代码时,它运行良好。然而,在我的身上,它显示“应用程序可能在其主线程上做太多工作”。
我通过重新启动 Android Studio [文件 -> 无效缓存 / 重新启动 -> 点击“无效并重新启动”]解决了我的问题。
【讨论】:
我不知道为什么您的解决方案有效。无论如何,谢谢。【参考方案12】:就我而言,这是因为我不小心在方法上设置了断点。一旦我清除它,消息就消失了,性能大大提高了。
【讨论】:
【参考方案13】:我的应用也有同样的问题。但它除了显示卡片列表和上面的文字外,并没有做任何事情。没有在后台运行。但经过一番调查后发现,卡片背景的图像集导致了这种情况,即使它很小(350kb)。然后我使用将图像转换为 9patch 图像 http://romannurik.github.io/AndroidAssetStudio/index.html。 这对我有用。
【讨论】:
【参考方案14】:我在开发一个在网格布局上使用大量可绘制 png 文件的应用程序时遇到了同样的问题。我还尝试尽可能优化我的代码..但它对我没有用..然后我尝试减小那些 png 的大小..并猜测它工作得很好..所以我的建议是减少可绘制资源的大小(如果有)..
【讨论】:
【参考方案15】:在这个问题上做了很多研发后,我得到了解决方案,
在我的情况下,我使用的是每 2 秒运行一次的服务,并且使用 runonUIThread,我想知道问题是否存在,但根本不存在。 我发现的下一个问题是我在 May App 中使用了大图像,这就是问题所在。
我删除了图像并设置了新图像。
结论:-查看您的代码是否有任何您使用的原始文件很大。
【讨论】:
【参考方案16】:首先阅读警告。它说主线程上有更多负载。所以你要做的就是在一个线程中运行更多工作的函数。
【讨论】:
【参考方案17】:正如我首先首选使用SVG
图像而不是所有其他类型的图像,如果不可能,请使用一些图像处理工具(例如Adobe Photoshop
或Fotosizer
)压缩所有PNG
和JPG
资源。最简单的方法之一是在线图像压缩工具,例如 this,它帮助我将所有图像文件减少到其初始大小的近 50%。
【讨论】:
【参考方案18】:尚未解决,但会解决。对于我的具有一个可组合功能(按钮)和逻辑来检查设备(模拟器)上是否存在“com.whatsapp”包的小型项目,我在启动模拟器时在同一日志中有以下内容:
I/Choreographer: Skipped 34 frames! The application may be doing too much work on its main thread.
【讨论】:
【参考方案19】:如果您在应用程序中使用异步/等待功能,这是正常的。
【讨论】:
以上是关于应用程序可能在其主线程上做了太多工作的主要内容,如果未能解决你的问题,请参考以下文章
Logcat 说 - 应用程序可能在其主线程上做了太多工作,并且错误消息说 - StringtoReal.invalidReal(string.boolean)line:63 [关闭]
Choreographer: Skipped frames : 应用程序可能在其主线程上做太多工作
对服务使用 AsyncTask 类仍然得到“跳过 31 帧!应用程序可能在其主线程上做太多工作。”。为啥?