可能大多数 Android 开发者都知道 findViewById
不是一个便宜的操作。我们大多数人都知道的另一件事是,您可以通过使用 View 层次结构的最小子树按 id 查找 View 来提高性能,例如:
<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/textview" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
在这种情况下,您可能想在
LinearLayout
中搜索与 id == @id/textview
但是,如果层次结构不是级联的,而是在每个级别上都有分支,并且您想在“叶子”上找到 View ,那么情况会怎样?你执行
findViewById
通过查找 parent 到达分支的底部,或者您是否执行 findViewById
在更大的子集上?我认为一个简单的答案是这取决于具体情况,但也许我们可以概括一下它真正取决于什么?谢谢
编辑:
通过更大的子集,我的意思是这样的:
<RelativeLayout android:id="@+id/r0">
<RelativeLayout
android:id="@+id/r1">
<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_3">
<LinearLayout
android:id="@+id/some_id_4">
<LinearLayout
android:id="@+id/some_id_5">
<TextView android:id="@+id/textview1" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:id="@+id/some_id_6">
<LinearLayout
android:id="@+id/some_id_7">
<LinearLayout
android:id="@+id/some_id_8">
<TextView android:id="@+id/textview2" />
<TextView android:id="@+id/textview3" />
<TextView android:id="@+id/textview4" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
所以问题是我是否想要
findViewById
TextView
浏览量 LinearLayout
与 @+id/some_id_8
,我应该对整个容器执行这个操作,还是应该findViewById
LinearLayout
与 @+id/some_id_8
并在此 View findViewById
所有 TextViews
?
最佳答案
如果您查找 View
,这绝对没有区别。直接或如果您先寻找 parent ,然后再寻找 child 。但是,例如,如果您想检索三个 TextViews
在 LinearLayout
id some_id_8
那么如果您首先查找 LinearLayout
,那么性能会更好然后是 TextViews
.但差别是微乎其微的。真正的问题是布局本身 (更多关于进一步向下)。
一般findViewById()
不是万恶之源。这可能是 ListView
中的问题如需拨打findViewById()
每次可能甚至多次getView()
调用,但这就是 View 持有者模式的用途。
当性能至关重要时,请调用 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()
只检查 id 是否有效,如果有效,则是 protected 方法 findViewTraversal()
叫做。在 View
它是这样实现的:protected View findViewTraversal(int id) {
if (id == mID) {
return this;
}
return null;
}
它只是检查传入的 id 是否等于
View
的 id并返回 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;
}
此方法顶部的第一个 if 与
View
中的相同实现,它只是检查传入的 id 是否等于 ViewGroup
的 id如果它这样做,它会返回自己。之后它遍历所有的 child 并调用 findViewById()
在每个 child 上,如果此调用的返回值不是 null
然后是 View
我们正在寻找的已经找到并将被退回。如果您想了解更多有关如何操作的详细信息
Views
或 ViewGroups
工作我建议你自己研究源代码!所以这一切似乎很简单。 View 层次结构本质上像一棵树一样遍历。这可能会使其变得非常昂贵或非常快,具体取决于
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
的数量成比例.但是 一般规则是,您应该尝试降低布局的复杂性以提高性能,并且您应该经常使用
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
作为 child :<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
的数量在布局较低。这同样适用于几乎所有其他与 View 相关的过程,如绘图、布局、测量。一切都会更快,因为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>
而这样的布局肯定会产生很大的性能提升。
关于android - findViewById 的效率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26037744/