Не имеет значения, если вы ищете View
напрямую или если вы сначала ищете родителя, а затем ребенка. Но если вы, например, хотите получить три TextViews
в LinearLayout
с идентификатором some_id_8
, тогда было бы лучше для производительности, если вы сначала посмотрите на LinearLayout
, а затем на TextViews
. Но разница незначительна. Настоящей проблемой является сама компоновка (подробнее об этом ниже).
И вообще findViewById()
не является источником всех зла. Это может быть проблемой в ListView
, если вам нужно позвонить findViewById()
, возможно, даже несколько раз за каждый звонок getView()
, но для этого нужен шаблон держателя.
Если производительность критическая, обратитесь к ней, чтобы вы могли позвонить по телефону findViewById()
как можно меньше. В Fragment
или Activity
вы можете посмотреть все Views
, которые вам понадобятся в onCreateView()
или onCreate()
. Если вы сохраните ссылки в нескольких переменных-членах, вам больше не придется называть их.
Теперь, чтобы объяснить, почему findViewById()
могут быть проблемы с производительностью, мы должны смотреть на его реализацию, this link leads to the Android 4.4.4 View source code:
public final View findViewById(int id) {
if (id < 0) {
return null;
}
return findViewTraversal(id);
}
Так findViewById()
просто проверяет, если идентификатор является действительным, и если это то защищенный метод findViewTraversal()
.В View
это реализовано так:
protected View findViewTraversal(int id) {
if (id == mID) {
return this;
}
return null;
}
Он просто проверяет, является ли переданная в идентификатор равен идентификатору View
и возвращает this
если это произойдет, в противном случае null
. Интересной частью является findViewTraversal()
реализация ViewGroup
, this links leads to the Android 4.4.4 ViewGroup source code:
protected View findViewTraversal(int id) {
if (id == mID) {
return this;
}
final View[] where = mChildren;
final int len = mChildrenCount;
for (int i = 0; i < len; i++) {
View v = where[i];
if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
v = v.findViewById(id);
if (v != null) {
return v;
}
}
}
return null;
}
первым, если в верхней части этого метода является то же самое, как и в View
реализации, он просто проверяет, является ли принятый в идентификатор равен идентификатору ViewGroup
, и если он делает это сам. После этого он перебирает всех детей и вызывает findViewById()
для каждого из детей, если возвращаемое значение этого звонка не null
, то найденный View
, который мы ищем, был найден и будет возвращен.
Если вы хотите получить более подробную информацию о том, как Views
или ViewGroups
работа, я предлагаю вам изучить исходный код самостоятельно!
Так что все это кажется довольно прямым. Иерархия представлений по существу пересекается, как дерево. И это может сделать его довольно дорогостоящим или довольно быстрым в зависимости от того, сколько Views
находится в вашем макете. Это не имеет значения, если ваш макет выглядит следующим образом:
<LinearLayout android:id="@+id/some_id_0">
<LinearLayout android:id="@+id/some_id_1">
<LinearLayout android:id="@+id/some_id_2">
<TextView android:id="@+id/textview0" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
Или, если это выглядит следующим образом:
<LinearLayout android:id="@+id/some_id_0">
<LinearLayout android:id="@+id/some_id_1" />
<LinearLayout android:id="@+id/some_id_2" />
<TextView android:id="@+id/textview0" />
</LinearLayout>
Поскольку количество Views
одинакова в обоих случаях, и производительность findViewById()
весы с размером Views
.
BUT Общее правило заключается в том, что вы должны попытаться уменьшить сложность макета для повышения производительности и что вы должны часто использовать RelativeLayout
. И это работает только потому, что, если вы уменьшите сложность, вы также уменьшите количество Views
в макете, а RelativeLayouts
очень хороши в уменьшении сложности. Позвольте мне проиллюстрировать, что образ у вас есть макет, как это:
<LinearLayout android:id="@+id/some_id_0">
<RelativeLayout android:id="@+id/some_id_5">
<LinearLayout android:id="@+id/some_id_1" />
<LinearLayout android:id="@+id/some_id_2" />
</RelativeLayout>
<RelativeLayout android:id="@+id/some_id_6">
<LinearLayout android:id="@+id/some_id_3" />
<LinearLayout android:id="@+id/some_id_4" />
</RelativeLayout>
</LinearLayout>
Представьте себе, что в этом случае оба выше RelativeLayouts
находятся только там, чтобы расположить внутренний LinearLayouts
каким-то особым образом, и внешний LinearLayout
только там расположите RelativeLayouts
друг под другом. Вы можете очень легко построить такую же компоновку с только RelativeLayout
как корень и четыре LinearLayouts
как дети:
<RelativeLayout android:id="@+id/some_id_0">
<LinearLayout android:id="@+id/some_id_1" />
<LinearLayout android:id="@+id/some_id_2" />
<LinearLayout android:id="@+id/some_id_3" />
<LinearLayout android:id="@+id/some_id_4" />
</RelativeLayout>
И производительность этого макета будет лучше, чем расположение выше, не потому, что RelativeLayout
каким-то образом на достижение максимальной эффективности лучше, чем LinearLayout
, а не потому, что макет более плоский, а просто потому, что сумма Views
в макете ниже. То же самое касается практически всех других связанных с представлением процессов, таких как рисование, макетирование, измерение. Все будет быстрее только потому, что сумма Views
в макете ниже.
И для возврата к исходному вопросу: Если вы хотите увеличить производительность, то уменьшите сложность вашего макета. Нет абсолютно никакой причины иметь так много вложенных LinearLayouts
. Ваше «большое подмножество» может быть почти наверняка сводятся к этому:
<RelativeLayout android:id="@+id/r0">
<TextView android:id="@+id/textview0" />
<TextView android:id="@+id/textview1" />
<TextView android:id="@+id/textview2" />
<TextView android:id="@+id/textview3" />
<TextView android:id="@+id/textview4" />
</RelativeLayout>
И такое расположение, несомненно, дает большой прирост производительности.
Можете ли вы объяснить больше своих 2 альтернатив, особенно «findViewById для большего подмножества»? – sotcha
Проверьте мои изменения. – overbet13
[по умолчанию обход] (http://androidxref.com/4.4.4_r1/xref/frameworks/base/core/java/android/view/ViewGroup.java#3246) - это глубина. Поиск поддерева сначала пахнет микро-оптимизацией, что делает код немного сложнее поддерживать. Мера, чтобы узнать, действительно ли это имеет значение. – laalto