Effizienz von findViewById

8

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:

%Vor%

In diesem Fall möchten Sie wahrscheinlich in LinearLayout mit id == @id/textview

suchen

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

BEARBEITEN:

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 ?

    
overbet13 25.09.2014, 11:41
quelle

2 Antworten

31

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 :

%Vor%

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:

%Vor%

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 :

%Vor%

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:

%Vor%

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:

%Vor%

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:

%Vor%

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:

%Vor%

Und solch ein Layout würde definitiv einen großen Leistungsschub bringen.

    
Xaver Kapeller 30.09.2014, 10:17
quelle
2

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.

    
miguel 11.06.2016 00:23
quelle