2013-03-06 15 views
9

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:

  1. Does Speicherverbrauch hängt wesentlich von der Ansichts-Klasse? Mit anderen Worten, gibt es einen wesentlichen Unterschied zwischen einem Button und einem TextView oder einem ImageView? Ich kann einen Click-Handler an jede Ansicht anhängen, so dass sie sich in der Verwendung nicht wesentlich unterscheiden.

  2. Beeinflussen Hintergrundbilder die Leistung? Wenn das gleiche Bild in N Ansichten eingestellt ist, wird es das Layout machen N mal schwerer? (Ich verstehe, dass diese Frage albern aussieht, aber trotzdem.)

  3. 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, die N mal breiter ist und einen sich wiederholenden Hintergrund hat?

  4. Bei einigen Layouts, was sollte zuerst optimiert werden: Gesamtanzahl der Ansichten, Verschachtelungsebenen oder etwas anderes?

  5. 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:

  1. Alle meine Ansichten werden hinzugefügt. Ich kann eine leichte Verlangsamung sehen, wenn sie hinzugefügt werden.
  2. 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.
  3. 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.

A tree-like hierarchy of messages.

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?

Antwort

7
  1. Verschiedene View ‚s gibt verschiedene Arten von Objekt. Einige nur draw() leichte Sachen, einige können große Bitmap-Objekte und Handler-Objekte und so weiter halten. Also, ja unterschiedliche View wird unterschiedliche Menge an RAM verbrauchen.

  2. Wenn dasselbe Bitmap-Objekt unter Ansichten gemeinsam genutzt wird, gibt es nur ein Objekt im RAM, jede Ansicht hat eine Referenzvariable, die auf dieses Objekt zeigt. Aber nicht so, wenn View zeichnet: Das Zeichnen der gleichen Bitmap n mal an n Stellen auf dem Bildschirm verbraucht n-mal die CPU und erzeugt n verschiedene bitmap_cache für jede Ansicht.

  3. Jede Seite eines 9-Patch-Bildes ist tatsächlich um 2 Pixel größer als das Originalbild. Sie sind nicht viel anders als eine Datei. Wenn sie gezeichnet werden, können beide skaliert werden und benötigen fast den gleichen Platz. Der einzige Unterschied ist, dass 9-Patch unterschiedlich skaliert werden.

    1. Das Festlegen des Hintergrunds der übergeordneten Ansicht ist besser, wenn die untergeordneten Ansichten transparent sind und der Hintergrund angezeigt wird.

    2. Sie können ein kleines Bild speichern und einen gekachelten Hintergrund festlegen, sodass es einen großen Bereich ausfüllen kann.

  4. Nesting ist zuerst optimiert werden, da alle Ansichten nicht zu einem bestimmten Zeitpunkt sichtbar sein könnte, sagen wir, nur ein paar Ansichten in Scroll-Layout sichtbar sind. Dann können Sie die Gesamtzahl der verwendeten Ansichten reduzieren. Nehmen Sie Hinweise von ListView: Gegeben, dass Benutzer nur eine Untermenge von Gesamtdaten auf einmal sehen wird, es die Ansichten neu Zyklen. und spart eine Menge Ressourcen.

  5. SDK bietet Hierarchy Viewer Werkzeug für diesen Zweck. Es zeigt eine vollständige Baumstruktur eines laufenden Layouts und setzt auch rote Flaggen für die trägen Teile des Layouts.

Ein gutes Layout ist das, was:

  1. Leicht gemessen (vermeiden komplexe gewichtete Breiten, Höhen und Ausrichtungen) werden. Für Beispiel statt layout_gravity="left" für jedes Kind, Eltern können gravity="left" haben.

  2. Hat weniger Tiefe, jede überlappende Ansicht fügt eine weitere Ebene hinzu, die zusammengesetzt werden soll, während der Bildschirm gezeichnet wird. Jede verschachtelte View-Struktur fragt nach einem verketteten Layout-Aufruf.

  3. Ist Smart und Re-Zyklen Ansichten, anstatt alle von ihnen zu erstellen.

  4. Wiederverwendet seine Teile: Tags wie <merge> und <include>.

Update: Antworten auf this question zeigen viele Ansätze für eine Baumansicht in Android.

+0

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? –

+0

@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. –

+1

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. –

Verwandte Themen