Die Anwendung arbeitet möglicherweise zu viel an ihrem Hauptthread

379

Ich bin neu in der Android SDK / API-Umgebung. Es ist das erste Mal, dass ich versuche, eine Handlung / ein Diagramm zu zeichnen. Ich habe versucht, verschiedene Arten von Beispielcodes im Emulator mit 3 verschiedenen freien Bibliotheken auszuführen. Auf dem Layoutbildschirm wird nichts angezeigt. Der Logcat wiederholt die folgende Meldung:

 W / Trace (1378): Unerwarteter Wert von nativeGetEnabledTags: 0
 Ich / Choreograf (1378): 55 Frames übersprungen! Die Anwendung arbeitet möglicherweise zu viel an ihrem Hauptthread.

Das Problem blieb nicht bestehen und das Diagramm funktionierte, als ich einen Beispielcode für eine Evaluierungskopie einer lizenzierten Bibliothek ausführte.

user2038135
quelle
2
Zeichnen Sie Ihre Diagramme in einem separaten Thread?
Areks
Vielen Dank für Ihren Kommentar. Ich habe die Frage bearbeitet, um sie klarer zu machen. Die Aktivität beim Ausführen zeigt an, dass ich eine Aktivität ausführe, deren Layout kein Design hat => einen weißen Bildschirm anzeigt.
user2038135
1
@Areks Nein, ich verwende keinen separaten Thread.
user2038135
1
Ich denke, Sie sollten, wird überhaupt nicht empfohlen, lange Operationen am Haupt-Thread auszuführen, da dies die gesamte Anwendung einfriert. Lesen Sie hier, wie Threads verwendet werden: stackoverflow.com/questions/3391272/… Ignorieren Sie den zu erledigenden Code die HTTP-Anfrage "und führen Sie dort einfach Ihre möglicherweise langen Operationen aus.
Areks
1
Warum Sie nicht versuchen zu suchen, finden Sie Informationen über den Choreografen. Ich empfehle Ihnen, diese Antwort zu lesen: stackoverflow.com/questions/11266535/…
Gabriel Esteban

Antworten:

479

entnommen aus: Android UI: Übersprungene Frames korrigieren

Jeder, der mit der Entwicklung einer Android-Anwendung beginnt, sieht diese Meldung auf logcat „Choreographer (abc): xx Frames übersprungen! Die Anwendung arbeitet möglicherweise zu viel an ihrem Haupt-Thread. “ Was bedeutet es eigentlich, warum sollten Sie besorgt sein und wie Sie es lösen können.

Dies bedeutet, dass die Verarbeitung Ihres Codes lange dauert und Frames deswegen übersprungen werden. Dies liegt möglicherweise an einer umfangreichen Verarbeitung, die Sie im Herzen Ihrer Anwendung oder am DB-Zugriff ausführen, oder an anderen Dingen, die den Thread dazu veranlassen hör für eine Weile auf.

Hier ist eine detailliertere Erklärung:

Mit Choreographer können sich Apps mit dem vsync verbinden und die Zeit richtig einstellen, um die Leistung zu verbessern.

Animationen in der Android-Ansicht verwenden Choreographer intern für denselben Zweck: um die Animationen richtig zu steuern und möglicherweise die Leistung zu verbessern.

Da Choreographer über alle vsync-Ereignisse informiert wird, kann ich feststellen, ob eine der vom Choreographer.post * apis weitergegebenen Runnables nicht in der Zeit eines Frames beendet wird und Frames übersprungen werden.

Nach meinem Verständnis kann Choreographer nur das Überspringen von Frames erkennen. Es ist nicht abzusehen, warum dies geschieht.

Die Meldung "Die Anwendung arbeitet möglicherweise zu viel an ihrem Hauptthread." könnte irreführend sein.

Quelle: Bedeutung der Choreographer-Nachrichten in Logcat

Warum sollten Sie besorgt sein

Wenn diese Meldung auf dem Android-Emulator angezeigt wird und die Anzahl der übersprungenen Frames relativ gering ist (<100), können Sie sicher sein, dass der Emulator langsam ist - was fast immer der Fall ist. Wenn jedoch die Anzahl der Frames übersprungen und groß ist und in der Größenordnung von 300+ liegt, kann es zu ernsthaften Problemen mit Ihrem Code kommen. Android-Geräte sind im Gegensatz zu iOS- und Windows-Geräten mit einer Vielzahl von Hardware ausgestattet. Der Arbeitsspeicher und die CPU variieren. Wenn Sie auf allen Geräten eine angemessene Leistung und Benutzererfahrung erzielen möchten, müssen Sie dieses Problem beheben. Wenn Frames übersprungen werden, ist die Benutzeroberfläche langsam und verzögert, was keine wünschenswerte Benutzererfahrung ist.

Wie man es repariert

Um dies zu beheben, müssen Knoten identifiziert werden, bei denen eine lange Verarbeitungsdauer vorliegt oder möglicherweise auftreten kann. Der beste Weg ist, die gesamte Verarbeitung durchzuführen, egal wie klein oder groß ein Thread ist, der vom Haupt-UI-Thread getrennt ist. Sei es der Zugriff auf Daten aus der SQLite-Datenbank oder das Ausführen von Hardcore-Berechnungen oder das einfache Sortieren eines Arrays - Führen Sie dies in einem anderen Thread durch

Jetzt gibt es hier einen Haken: Sie erstellen einen neuen Thread für diese Vorgänge. Wenn Sie Ihre Anwendung ausführen, stürzt dieser ab und sagt: "Nur der ursprüngliche Thread, der eine Ansichtshierarchie erstellt hat, kann seine Ansichten berühren." Sie müssen diese Tatsache kennen, dass die Benutzeroberfläche in Android nur vom Hauptthread oder vom UI-Thread geändert werden kann. Jeder andere Thread, der dies versucht, schlägt fehl und stürzt mit diesem Fehler ab. Sie müssen lediglich eine neue ausführbare Datei in runOnUiThread erstellen und in dieser ausführbaren Datei alle Vorgänge ausführen, die die Benutzeroberfläche betreffen. Finden Sie ein Beispiel hier .

Wir haben also Thread und Runnable für die Verarbeitung von Daten aus dem Haupt-Thread. Was noch? Es gibt AsyncTask in Android, das es ermöglicht, Langzeitprozesse auf dem UI-Thread durchzuführen. Dies ist am nützlichsten, wenn Ihre Anwendungen daten- oder web-API-gesteuert sind oder komplexe Benutzeroberflächen verwenden, wie sie mit Canvas erstellt wurden. Die Stärke von AsyncTask besteht darin, dass Sie Dinge im Hintergrund erledigen können. Sobald Sie mit der Verarbeitung fertig sind, können Sie einfach die erforderlichen Aktionen auf der Benutzeroberfläche ausführen, ohne Verzögerungseffekte zu verursachen. Dies ist möglich, weil sich die AsyncTask vom UI-Thread der Aktivität ableitet. Alle Vorgänge, die Sie über AsyncTask auf der UI ausführen, sind andere Threads als der Haupt-UI-Thread. Keine Behinderung der Benutzerinteraktion.

Das ist es also, was Sie wissen müssen, um reibungslose Android-Anwendungen zu erstellen. Soweit ich weiß, erhält jeder Anfänger diese Nachricht auf seiner Konsole.

Jorgesys
quelle
41
Ich habe nur eine App, in der sich das Hintergrundbild der Schaltfläche ändert und die Schaltfläche nicht angeklickt werden kann, wenn ich auf eine Schaltfläche klicke. Wie mache ich zu viel Arbeit :(
Remian8985
1
@ Remian8985 - Die Änderung des Hintergrundbilds für die Schaltfläche (vorausgesetzt, Sie laden dieses Bild herunter) sollte in einer AsyncTask durchgeführt werden. Dies bedeutet, dass dieser Download-Hintergrundvorgang ausgeführt und das Ergebnis im UI-Thread veröffentlicht wird (das Bild zurückgeben). Siehe Android Referenz Link
BenJaminSila
11
@BenJaminSila Hintergrund in AsyncTask ändern? "Ja wirklich?"
Benutzer25
11
@ user25 "vorausgesetzt, Sie laden dieses Bild herunter"
forresthopkinsa
"Wenn diese Meldung auf dem Android-Emulator angezeigt wird und die Anzahl der übersprungenen Frames relativ gering ist (<100), können Sie sicher sein, dass der Emulator langsam ist." Gilt dies auch heute noch? Emulatoren werden ziemlich schnell, oder?
Robin Dijkhof
243

Wie andere oben antworteten: "55 Frames übersprungen!" bedeutet, dass sich in Ihrer Anwendung eine schwere Verarbeitung befindet.

Für meinen Fall gibt es keinen schweren Prozess in meiner Bewerbung. Ich habe alles doppelt und dreifach überprüft und den Prozess entfernt, den ich für etwas schwer halte.

Ich entfernte Fragmente, Aktivitäten, Bibliotheken, bis nur noch das Skelett übrig war. Trotzdem verschwand das Problem nicht. Ich habe beschlossen, die Ressourcen zu überprüfen, und festgestellt, dass einige der von mir verwendeten Symbole und Hintergründe ziemlich groß sind, da ich vergessen habe, die Größe dieser Ressourcen zu überprüfen.

Mein Vorschlag ist also, wenn keine der oben genannten Antworten hilft, können Sie auch die Größe Ihrer Ressourcendateien überprüfen.

Sithu
quelle
1
Hat auch für mich gearbeitet. Ich hatte eine Anwendung, die sehr wenig Arbeit erledigte, aber langsam und schleppend war. Ich bekam immer wieder übersprungene Frames-Protokolle. Nachdem ich den Hintergrund von meiner Aktivität entfernt hatte, war alles in Ordnung. Vielen Dank!
Akrabi
Tolle Antwort, ich glaube das war genau mein Problem. Ich habe eine Reihe anderer (ziemlich komplizierter) Lösungen ausprobiert und die App war genauso langsam. Ich habe alle Webdienste entfernt und versucht, meinen Code bis auf die Knochen zu optimieren. Hat nicht funktioniert, dann habe ich das gesehen. Sobald ich mein Hintergrundbild entfernt habe (das größte Bild, das ich habe), funktioniert die App so schnell wie möglich, selbst mit dem alten "langsamen" Code.
M Barbosa
du hast meinen Tag gerettet!
Nicolas Mastromarino
:) Du bist ein absolutes Genie.
Metin Ilhan
@batsheva es ist nicht notwendig, 1 KB zu sein. Dies hängt von Ihren Anforderungen ab. Nehmen wir an, Sie benötigen ein klareres Bild. Möglicherweise verwenden Sie eine höhere Auflösung. Stellen Sie jedoch sicher, dass Sie die verschiedenen Ressourcenordner in verschiedene Größen aufteilen.
Sithu
61

Ich hatte auch das gleiche Problem.
Meins war ein Fall, in dem ich ein Hintergrundbild verwendete, das sich in Drawables befand. Dieses bestimmte Bild hatte eine Größe von ca. 130 KB und wurde während des Begrüßungsbildschirms und der Startseite in meiner Android-App verwendet.

Lösung - Ich habe gerade dieses bestimmte Bild von drawables in den Ordner drawables-xxx verschoben und konnte viel Speicherplatz im Hintergrund freigeben, und die überspringenden Frames wurden nicht mehr übersprungen.

Update Verwenden Sie den zeichnbaren Ressourcenordner 'nodp' zum Speichern von Drawables-Hintergrunddateien.
Wird ein dichtequalifizierter Zeichenordner oder ein Zeichen-Nodpi Vorrang haben?

Prakhar1001
quelle
7
Ich habe mein großes Hintergrundbild von Drawable auf Mimap-xxxhdpi verschoben und es hat den Trick gemacht!
Bgplaya
Du hast viel geholfen. Danke
N.Droid
2
Diese Lösung macht den Trick. Ich verwende drawable-xxxhdpistattdessen Ordner, drawablewas den verwendeten Speicher drastisch reduziert (~ 70 Prozent weniger). Gut zu wissen, dass Bildschirme mit derselben Größe in der DPI-Größe variieren. Das Verhältnis in Pixeln zwischen ihnen ist ldpi = 1:0.75, mdpi = 1:1, hdpi = 1:1.5, xhdpi = 1:2, xxhdpi = 1:3, xxxhdpi = 1:4. Wenn drawable-xxxhdpiSie den Ordner verwenden, können Sie die Bilder auf die Bildschirmgröße Ihres Geräts verkleinern, was den Speicher- und CPU-Verbrauch verringert.
Timo Bähr
2
Durch das Verschieben von Bildern von drawablenach wird drawable-nodpiverhindert , dass die Anwendung abgerufen wird Out of Memory Error.
Shruti
Oh mein Gott ... danke! Ich hatte ein Bild im Zeichenordner und dies machte meine App höllisch langsam (obwohl das Bild nur 100 KB groß war !!!). Nach dem Generieren der drawable-xxx-Dateien (ich habe den Android Drawable Importer verwendet) ist meine App verdammt schnell. Vielen Dank!
error1337
20

Eine weitere häufige Ursache für Verzögerungen im UI-Thread ist der Zugriff auf SharedPreferences. Wenn Sie PreferenceManager.getSharedPreferenceszum ersten Mal eine und ähnliche Methoden aufrufen , wird die zugehörige XML-Datei sofort geladen und im selben Thread analysiert .

Eine gute Möglichkeit, dieses Problem zu bekämpfen, besteht darin, das erste Laden von SharedPreference aus dem Hintergrundthread auszulösen, der so früh wie möglich gestartet wird (z. B. aus onCreateIhrer Anwendungsklasse). Auf diese Weise wird das Voreinstellungsobjekt möglicherweise bereits zu dem Zeitpunkt erstellt, zu dem Sie es verwenden möchten.

Leider ist manchmal das Lesen von Einstellungsdateien in frühen Startphasen erforderlich (z. B. in der ersten Aktivität oder sogar in der Anwendung selbst). In solchen Fällen ist es immer noch möglich, das Blockieren der Benutzeroberfläche durch Verwendung zu vermeiden MessageQueue.IdleHandler. Führen Sie alle anderen Schritte aus, die Sie für den Hauptthread ausführen müssen, und installieren Sie dann den IdleHandler, um Code auszuführen, sobald Ihre Aktivität vollständig gezeichnet wurde. In diesem Runnable sollten Sie auf SharedPreferences zugreifen können, ohne zu viele Zeichenvorgänge zu verzögern und Choreographer unglücklich zu machen.

user1643723
quelle
1
In diesem Fall sollten Sie die Methode apply () anstelle von commit () bevorzugen. Die Methode apply () kann die Benutzeroberfläche nicht blockieren. Sie können von hier aus schauen developer.android.com/training/data-storage/shared-preferences
Emre Gürses
16

Versuchen Sie, die folgenden Strategien zu verwenden, um die Leistung Ihrer App zu verbessern:

  • Verwenden Sie nach Möglichkeit die Multithreading-Programmierung. Die Leistungsvorteile sind enorm, selbst wenn Ihr Smartphone einen Kern hat (Threads können in verschiedenen Kernen ausgeführt werden, wenn der Prozessor zwei oder mehr hat). Es ist nützlich, Ihre App-Logik von der Benutzeroberfläche zu trennen. Verwenden Sie Java-Threads, AsyncTask oder IntentService. Überprüfen Sie dies .
  • Lesen und befolgen Sie die verschiedenen Leistungstipps der Android-Entwicklungswebsite. Überprüfen Sie hier .
MigDus
quelle
3
Für Ihren ersten Link müssen Sie "... ein validiertes Konto haben ...", um darauf zugreifen zu können.
Chornge
9

Ich hatte das gleiche Problem. Android Emulator funktionierte perfekt unter Android <6.0. Als ich den Emulator Nexus 5 (Android 6.0) verwendete, arbeitete die App sehr langsam mitI/Choreographer: Skipped frames in den Protokollen .

Also habe ich dieses Problem gelöst, indem ich die hardwareAcceleratedOption " Manifest-Datei" so geändert habe , dass sie mir truegefällt:

<?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>
Phänomen
quelle
8

Ich bin kein Experte, aber ich habe diese Debug-Meldung erhalten, als ich Daten von meiner Android-Anwendung an einen Webserver senden wollte. Obwohl ich die AsyncTask-Klasse verwendet und die Datenübertragung im Hintergrund durchgeführt habe, habe ich zum Abrufen der Ergebnisdaten vom Server die get () -Methode der AsyncTask-Klasse verwendet, die die Benutzeroberfläche synchronisiert, was bedeutet, dass Ihre Benutzeroberfläche zu lange wartet. Mein Rat ist daher, dass Ihre App alle netzwerkorientierten Aufgaben in einem separaten Thread ausführt.

Saba
quelle
6

Optimieren Sie Ihre Bilder ... Verwenden Sie keine Bilder mit mehr als 100 KB ... Das Laden von Bildern beansprucht zu viel CPU und führt dazu, dass Ihre App hängt.

HarshitG
quelle
4
Verringern Sie die Bildgröße entweder mit Java-Code oder verwenden Sie Photoshop, um Bilder zuzuschneiden. Komprimieren Sie Bilder auch mit compressor.io
zuzuschneiden HarshitG
5

Ich hatte das gleiche Problem. In meinem Fall hatte ich 2 verschachtelte relative Layouts. RelativeLayout muss immer zwei Messdurchgänge ausführen. Wenn Sie RelativeLayouts verschachteln, erhalten Sie einen exponentiellen Messalgorithmus.

Radoslav
quelle
4

Dies geschieht normalerweise, wenn Sie große Prozesse im Hauptthread ausführen. Es ist in Ordnung, Frames mit weniger als 200 Frames zu überspringen. Wenn Sie jedoch mehr als 200 übersprungene Frames haben, kann dies den Anwendungs-UI-Thread verlangsamen. Was Sie tun können, ist, diese Prozesse in einem neuen Thread namens Worker-Thread auszuführen. Wenn Sie danach auf UI-Thread zugreifen und etwas mit ihm tun möchten (z. B. etwas mit Ansichten, findView usw. tun), können Sie Handler oder runOnUiThread verwenden (Ich mag das mehr), um die Verarbeitungsergebnisse anzuzeigen. Dies löst das Problem absolut. Die Verwendung von Worker-Threads ist sehr nützlich oder muss in diesen Fällen sogar verwendet werden.

Hossein Karami
quelle
1

Ich hatte das gleiche Problem. Als ich den Code auf einem anderen Computer ausführte, funktionierte er einwandfrei. Bei mir wurde jedoch "Die Anwendung arbeitet möglicherweise zu viel an ihrem Hauptthread" angezeigt.

Ich habe mein Problem durch einen Neustart von Android Studio gelöst [Datei -> Ungültige Caches / Neustart -> Klicken Sie auf "Ungültig machen und neu starten"].

Sonida
quelle
Ich weiß nicht, warum Ihre Lösung funktioniert hat. Trotzdem danke.
Bhuvanesh BS
1

In meinem Fall lag es daran, dass ich versehentlich einen Haltepunkt für eine Methode festgelegt hatte. Nachdem ich es gelöscht hatte, verschwand die Nachricht und die Leistung verbesserte sich erheblich.

FractalBob
quelle
0

Meine App hatte das gleiche Problem. Aber es wurde nichts anderes getan, als eine Liste mit Karten und Text darauf anzuzeigen. Nichts läuft im Hintergrund. Aber nach einigen Nachforschungen stellte sich heraus, dass das für den Kartenhintergrund festgelegte Bild dies verursachte, obwohl es klein war (350 KB). Dann habe ich das Bild mit http://romannurik.github.io/AndroidAssetStudio/index.html in 9patch-Bilder konvertiert .
Das hat bei mir funktioniert.

naamadheya
quelle
0

Nachdem ich viel Forschung und Entwicklung zu diesem Thema betrieben hatte, bekam ich die Lösung:

In meinem Fall verwende ich einen Dienst, der alle 2 Sekunden ausgeführt wird, und mit dem runonUIThread habe ich mich gefragt, ob das Problem vorhanden ist, aber überhaupt nicht. Das nächste Problem, das ich gefunden habe, ist, dass ich in der May-App ein großes Bild verwende, und das ist das Problem.

Ich habe die Bilder entfernt und neue Bilder eingestellt.

Fazit: - Sehen Sie in Ihrem Code nach, ob eine von Ihnen verwendete Rohdatei groß ist.

Hector Morris
quelle
0

Lesen Sie zuerst die Warnung. Es heißt mehr Belastung des Hauptfadens. Sie müssen also nur Funktionen mit mehr Arbeit in einem Thread ausführen.

de_billa_
quelle
-1

Ich habe das gleiche Problem bei der Entwicklung einer App, die viele zeichnbare PNG-Dateien im Rasterlayout verwendet. Ich habe auch versucht, meinen Code so weit wie möglich zu optimieren. Aber es hat bei mir nicht geklappt. Dann habe ich versucht, die Größe dieser PNG zu reduzieren. Und ich denke, es funktioniert absolut einwandfrei. Mein Vorschlag ist also, sie zu reduzieren Größe der ziehbaren Ressourcen, falls vorhanden.

Shubham Ranakoti
quelle