gpt4 book ai didi

android - findViewById 的效率

转载 作者:可可西里 更新时间:2023-11-01 19:09:54 30 4
gpt4 key购买 nike

可能大多数 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 。但是,例如,如果您想检索三个 TextViewsLinearLayout id some_id_8那么如果您首先查找 LinearLayout,那么性能会更好然后是 TextViews .但差别是微乎其微的。真正的问题是布局本身 (更多关于进一步向下)。

一般findViewById()不是万恶之源。这可能是 ListView 中的问题如需拨打findViewById()每次可能甚至多次getView()调用,但这就是 View 持有者模式的用途。

当性能至关重要时,请调用 findViewById()尽可能少。在 FragmentActivity您可以查找所有 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我们正在寻找的已经找到并将被退回。

如果您想了解更多有关如何操作的详细信息 ViewsViewGroups工作我建议你自己研究源代码!

所以这一切似乎很简单。 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/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com