Ich möchte die wichtigsten Probleme der Android-Layouts und -Ansichten herausfinden. Ich recherchiere jetzt, aber vielleicht hat jemand schon Antworten.Wie ist die Anzahl der Ansichten begrenzt?
Ich habe eine RelativeLayout
, die dynamisch mit Ansichten aufgefüllt wird. Im Grunde lädt die Anwendung einen Forum-Thread in XML und rendert den Diskussions-Baum so, dass jede Nachricht in einer eigenen Gruppe von Ansichten angezeigt wird. Ich habe mich entschieden, WebView
nicht zu verwenden, da ich einige clientseitige Funktionen implementieren möchte, die bei benutzerdefinierten Ansichten einfacher als auf HTML-Seite sein sollten.
Allerdings hat dieser Ansatz einen großen Fehler: Es ist schwer. Das erste Problem (welches ich gelöst habe) war nesting of views. Dies ist jetzt kein Problem, mein Layout ist fast flach, so dass die maximale Tiefe 10-12 ist (gezählt vom obersten PhoneWindow $ DecorView, die tatsächliche Tiefe hängt von den Daten ab).
Jetzt habe ich die nächste Grenze erreicht, die irgendwie mit Ressourcenverbrauch der Ansichten verbunden ist (oder durch verursacht wird). Nach dem Laden der Daten bleibt die Anwendung eine Weile stehen, um das Layout zu erstellen (erstellt die Ansichten und füllt sie mit den Daten), und die Hangzeit scheint linear mit der Datengröße zu wachsen; Wenn die Daten groß genug sind, wird die Ansicht nie angezeigt (schließlich schlägt das System vor, die Anwendung zu schließen, weil sie nicht reagiert). Jetzt
die Fragen:
Does Speicherverbrauch hängt wesentlich von der Ansichts-Klasse? Mit anderen Worten, gibt es einen wesentlichen Unterschied zwischen einem
Button
und einemTextView
oder einemImageView
? Ich kann einen Click-Handler an jede Ansicht anhängen, so dass sie sich in der Verwendung nicht wesentlich unterscheiden.Beeinflussen Hintergrundbilder die Leistung? Wenn das gleiche Bild in
N
Ansichten eingestellt ist, wird es das Layout machenN
mal schwerer? (Ich verstehe, dass diese Frage albern aussieht, aber trotzdem.)Sind Neun-Patch-Bilder deutlich schwerer als normale? Was ist besser: um
N
Ansichten zu erstellen, wo jedes einige Hintergrundbilder hat, oder um eine Ansicht zu machen, dieN
mal breiter ist und einen sich wiederholenden Hintergrund hat?Bei einigen Layouts, was sollte zuerst optimiert werden: Gesamtanzahl der Ansichten, Verschachtelungsebenen oder etwas anderes?
Die interessantesten. Ist es möglich, die von der Aktivität und ihren Ansichten verbrauchten Ressourcen zu messen oder zumindest zu schätzen? Wenn ich etwas ändere, wie könnte ich sehen, dass ich den richtigen Weg gehe?
UPDATE
Dank User117, einige Fragen, die ich oben jetzt beantwortet werden gebeten. Ich habe den Hierarchie-Viewer verwendet und mein Layout optimiert: Im Vergleich zu dem, was ich vorher hatte, ist die Gesamtzahl der Ansichten jetzt fast doppelt reduziert, und die Verschachtelung ist ebenfalls reduziert.
Allerdings hängt die Anwendung immer noch auf einem großen Forum-Thread.
UPDATE 2
Ich habe den Debugger an meinem Gerät und fand verbunden, dass die Anwendung aus dem Speicher erhält.
Aber was ist sehr unerwartet für mich ist, dass der Fehler auftritt, nachdem ich das Layout bevölkern. Die Reihenfolge ist wie folgt:
- Alle meine Ansichten werden hinzugefügt. Ich kann eine leichte Verlangsamung sehen, wenn sie hinzugefügt werden.
- Fast nichts passiert für ein paar Sekunden. Während dieser Zeit werden einige Info-Nachrichten im Protokoll erzeugt, die identisch sind:
[global] Loaded time zone names for en_US in XXXXms
, der einzige Unterschied ist die Anzahl der Millisekunden. - Die Speicherfehlermeldung wird ausgegeben:
[dalvikvm-heap] Out of memory on a N-byte allocation
(die tatsächliche Größe variiert). Die lange Fehlerberichterstattung beginnt.
Was bedeutet das? Sieht so aus, als hätte das Rendering seine eigenen Anforderungen, die beträchtlich sein können.
UPDATE 3
Endlich habe ich die Kernfrage gefunden. Hier ist ein Screenshot von meiner Anwendung, siehe eine Erklärung unter dem Bild.
Jede Nachricht besteht aus einem runden Knopf, der die Antworten und einen Rotanteil Rahmen rechts von dem Knopf ein- oder ausgeblendet. Dies ist sehr einfach und erfordert nur 6 Ansichten einschließlich der Layouts.
Das Problem ist der Einzug mit diesen Verbindungslinien, die zeigen, welche Nachricht zu welcher verwandt ist.
In meiner aktuellen Implementierung besteht die Einrückung aus kleinen ImageView
, die jeweils ein quadratisches Bild enthalten, das entweder einen leeren Raum oder eine vertikale Linie oder einen T-ähnlichen Verbinder oder eine L-ähnliche Ecke zeigt. Alle diese Ansichten sind innerhalb des großen RelativeLayout
, der den gesamten Diskussionsbaum enthält, miteinander ausgerichtet.
Dies funktioniert gut für kleine und mittlere Bäume (bis zu einigen hundert Nachrichten), aber wenn ich versuche, einen großen Baum (2K + Nachrichten) zu laden, bekomme ich das Ergebnis in UPDATE 2 oben erklärt.
Offensichtlich habe ich hier zwei Probleme. Ich spawne eine große Anzahl von Ansichten, die alle Speicher verbrauchen, und diese Ansichten sind ImageView
, die mehr Speicher für das Rendern benötigen, da sie eine Bitmap rendern und daher Grafikcaches erstellen (laut Erklärung von User117 in den Kommentaren).
Ich habe versucht, das Laden der Bilder in die Einrückungsansichten zu deaktivieren, hat aber keinen Effekt. Es scheint so zu sein, dass das Hinzufügen einer großen Anzahl von Ansichten ausreicht, um den gesamten verfügbaren Speicher zu verbrauchen.
Meine andere Idee war, ein Einrückungsbild für jede Nachricht zu erstellen, die alle Rohre und Ecken enthalten würde, so dass jede Nachricht die einzige Einrückungsansicht statt 10 oder 20 hätte. Aber das ist noch aufwendiger: Ich habe aus dem Speicher in der Mitte des Layouts zu füllen. (Ich habe die Bilder in einer Karte zwischengespeichert, so dass zwei Bitmaps mit identischer Bildfolge nicht erstellt wurden, das hat nicht geholfen.)
Also komme ich zu dem Schluss, dass ich in einer Sackgasse bin. Ist es überhaupt möglich, alle diese Zeilen gleichzeitig zu zeichnen?
Mit einer einfachen Funktion: eine Schaltfläche mit Grafiken, die eine onClick-Aktion hat, könnte ich mehrere Möglichkeiten gehen: 1) Einfügen einer Schaltfläche mit einem Hintergrundbild, 2) Einfügen einer ImageView, 3) Einfügen einer TextView 'und weisen Sie diesem Objekt einen Klick-Handler zu, unabhängig davon, welche Klasse verwendet wird. Gibt es einen Unterschied in der Leistung zwischen diesen Möglichkeiten? –
@AlexanderDunaev Nun, ein 'Button' verwendet OS-Standard-Visuals,' ImageView' lädt etwas mehr von Ihren App-Ressourcen und 'TextView' enthält zusätzlichen Code zum Messen/Rendern und den gleichen Handler-Code. Die individuelle Differenz in den Zeiten, in denen diese Ansichten sich selbst verwalten/neu zeichnen, wäre nicht zulässig. Nun, wenn Sie etwa tausend davon in Ihrem Layout haben, dann können die Gesamtunterschiede erheblich sein. Auch "Button", "ImageButton", "ImageView", "TextView" usw. sind für bestimmte Zwecke gedacht und werden am besten für diesen Zweck verwendet. –
Ich zweite @ User117 die Antwort, vor allem Punkt 4). Erstellen Sie keine Ansichten in möglicherweise langen (hierarchischen) Listen, die nicht sichtbar sind. Ändern Sie stattdessen die * Inhalte * der sichtbaren Ansichten, indem Sie die enthaltenen Daten in die Ansicht scrollen, ähnlich wie bei ListView und den zugehörigen Ansichten. Z.B. In Ihrem Screenshot sollten nicht mehr als 11 oder 12 Zeilen erstellt werden, die jeweils eine Elternansicht, eine Bildansicht und eine Textansicht mit einigen benutzerdefinierten Zeichnungen (Linien) enthalten. Alles in allem nicht mehr als 36 Views in diesem Fall. –