Wahrscheinlich wissen die meisten Android-Entwickler, dass findViewById
keine billige Operation ist. Eine andere Sache, die die meisten von uns wissen, ist, dass Sie die Leistung steigern können, indem Sie den kleinsten Teilbaum der Ansichtshierarchie verwenden, um Ansichten anhand ihrer ID zu finden, zum Beispiel:
In diesem Fall möchten Sie wahrscheinlich in LinearLayout
mit id == @id/textview
Aber was ist der Fall, wenn die Hierarchie nicht kaskadiert, sondern auf jeder Ebene verzweigt und Sie die Ansichten auf den "Blättern" finden wollen? Führt du findViewById
aus, um zum Ende des Zweigs zu gelangen, indem du Eltern findest, oder führst du findViewById
für eine größere Teilmenge aus? Ich denke, eine einfache Antwort wäre, dass es auf den Fall ankommt, aber vielleicht könnten wir ein bisschen verallgemeinern, worauf es wirklich ankommt?
Danke
Mit einer größeren Teilmenge meine ich so etwas:
%Vor% Also die Frage wäre, wenn ich findViewById
die TextView
Ansichten in LinearLayout
mit @+id/some_id_8
möchte, sollte ich diese Operation für den gesamten Container ausführen, oder ich sollte findViewById
die LinearLayout
mit @+id/some_id_8
und in dieser Ansicht findViewById
all TextViews
?
Es macht keinen Unterschied, ob Sie direkt nach dem View
suchen oder zuerst nach einem Elternteil und dann nach dem Kind suchen. Wenn Sie jedoch beispielsweise die drei TextViews
in LinearLayout
mit der ID some_id_8
abrufen möchten, wäre die Leistung besser, wenn Sie zuerst nach LinearLayout
und dann nach TextViews
suchen. Aber der Unterschied ist winzig. Das eigentliche Problem ist das Layout selbst (mehr dazu weiter unten).
Und generell ist findViewById()
nicht die Quelle allen Übels. Es kann ein Problem in ListView
sein, wenn Sie findViewById()
möglicherweise sogar mehrmals während jedes getView()
-Aufrufs aufrufen müssen, aber dafür ist das Ansichtshalter-Muster gedacht.
Wenn die Leistung kritisch ist, sorgen Sie dafür, dass Sie findViewById()
so wenig wie möglich aufrufen. In Fragment
oder Activity
können Sie nach allen Views
suchen, die Sie jemals benötigen werden in onCreateView()
oder onCreate()
. Wenn Sie die Referenzen in einigen Member-Variablen speichern, müssen Sie sie nie mehr aufrufen.
Nun, um zu erklären, warum findViewById()
ein Performance-Problem sein kann, müssen wir uns die Implementierung ansehen, dieser Link führt zum Android 4.4.4 View-Quellcode :
So prüft% code_% nur, ob die ID gültig ist, und wenn dies der Fall ist, wird die geschützte Methode findViewById()
aufgerufen. In einem findViewTraversal()
wird es wie folgt implementiert:
Es prüft nur, ob die übergebene ID der ID von View
entspricht und gibt View
zurück, wenn dies der Fall ist, andernfalls this
. Der interessante Teil ist die null
Implementierung von findViewTraversal()
, diese Links führen zum Android 4.4.4 ViewGroup-Quellcode :
Der erste, wenn am Anfang dieser Methode der gleiche wie in der ViewGroup
Implementierung ist, es überprüft nur, ob die übergebene ID gleich der ID von View
ist und wenn es dies tut, gibt es sich selbst zurück. Danach durchläuft es alle untergeordneten Elemente und ruft ViewGroup
für jedes der untergeordneten Elemente auf. Wenn der Rückgabewert dieses Aufrufs nicht findViewById()
ist, dann wurde das null
, nach dem wir suchen, gefunden und wird zurückgegeben.
Wenn Sie mehr über die Funktionsweise von View
oder Views
wissen möchten, empfehle ich Ihnen, den Quellcode selbst zu studieren!
Das scheint alles ziemlich geradlinig zu sein. Die Ansichtshierarchie wird im Wesentlichen wie ein Baum durchlaufen. Und das kann es ziemlich teuer oder ziemlich schnell machen, abhängig davon, wie viele ViewGroups
in deinem Layout sind. Es spielt keine Rolle, ob Ihr Layout so aussieht:
Oder wenn es so aussieht:
%Vor% Weil die Menge von Views
in beiden Fällen gleich ist und die Leistung von Views
mit der Menge von findViewById()
skaliert.
ABER Die allgemeine Regel lautet, dass Sie versuchen sollten, die Komplexität des Layouts zu reduzieren, um die Leistung zu erhöhen, und dass Sie häufig Views
verwenden sollten. Und das funktioniert nur, weil Sie, wenn Sie die Komplexität reduzieren, auch die Menge von RelativeLayout
im Layout reduzieren und Views
sehr gut, um die Komplexität zu reduzieren. Lass mich das illustrieren, du hast ein Layout wie dieses:
Stellen Sie sich vor, dass in diesem Fall beide oben genannten RelativeLayouts
nur dazu da sind, die innere RelativeLayouts
auf eine spezielle Art zu positionieren und die äußere LinearLayouts
nur dazu da ist, die LinearLayout
untereinander zu positionieren. Sie können sehr einfach das gleiche Layout mit nur einem RelativeLayouts
als root und den vier RelativeLayout
as children erstellen:
Und die Leistung dieses Layouts ist besser als das obige Layout, nicht weil LinearLayouts
irgendwie leistungsmäßig besser ist als RelativeLayout
und nicht weil das Layout flacher ist, sondern einfach weil die Menge von LinearLayout
im Layout ist niedriger. Gleiches gilt für fast alle anderen sichtbezogenen Prozesse wie Zeichnen, Layout, Messen. Alles wird schneller, nur weil die Menge von Views
im Layout niedriger ist.
Und um zu Ihrer ursprünglichen Frage zurückzukehren: Wenn Sie eine Leistungssteigerung wünschen, reduzieren Sie die Komplexität Ihres Layouts. Es gibt absolut keinen Grund so viele verschachtelte Views
zu haben. Ihre "große Teilmenge" kann fast sicher darauf reduziert werden:
Und solch ein Layout würde definitiv einen großen Leistungsschub bringen.
Wenn ich mir diesen Android-Quellcode ansehe, sehe ich einfach nicht, wie findViewById überhaupt teuer ist. Es ist im Grunde eine einfache Schleife, ich weiß, dass es rekursiv ist, so dass Sie die Strafe bezahlen, den Stapel ständig zu wechseln, aber selbst der komplizierteste Bildschirm wird in der Größenordnung von Dutzenden von Ansichten sein, nicht für Tausende, außer für recycelte Listen. Ich denke, wir brauchen Benchmarks auf Low-End-Geräten, um zu wissen, ob es wirklich ein Problem ist.
Tags und Links android android-layout performance findviewbyid