ove*_*t13 13 performance android android-layout findviewbyid
可能大多数Android开发者都知道这findViewById不是一个廉价的操作.我们大多数人都知道的另一件事是,您可以通过使用视图层次结构的最小子树来查找其ID的视图,从而提高性能,例如:
<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>
Run Code Online (Sandbox Code Playgroud)
在这种情况下,你可能希望在搜索LinearLayout与id == @id/textview
但是,如果层次结构不是级联,而是在每个级别上进行分支,并且您想要在"叶子"上找到视图,那么会发生什么情况呢?您是findViewById通过寻找父母来执行到达分支的底部,还是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>
Run Code Online (Sandbox Code Playgroud)
所以现在的问题是,如果我想findViewById在TextView视图中LinearLayout使用@+id/some_id_8,我应该在整个容器上执行此操作,或者我应该findViewById在LinearLayout使用@+id/some_id_8,并在此视图findViewById所有TextViews?
Xav*_*ler 35
如果你View直接寻找,或者如果你首先寻找父母,然后寻找孩子,那么它绝对没有区别.但是,如果您想要使用id 检索三个TextViews,那么如果您首先查找然后查找,那么性能会更好.但差别很小.真正的问题是布局本身(更多的是进一步向下).LinearLayoutsome_id_8LinearLayoutTextViews
而且一般findViewById()不是万恶之源.ListView如果你findViewById()在每次getView()调用期间都需要多次调用,这可能是一个问题,但这就是视图持有者模式的用途.
当性能至关重要时,请确保您findViewById()尽可能少地打电话.在一个Fragment或Activity你可以找到Views你需要的所有onCreateView()或onCreate().如果将引用保存在几个成员变量中,则永远不必再次调用它.
现在解释为什么findViewById()可能是性能问题我们必须看看它的实现,这个链接导致Android 4.4.4查看源代码:
public final View findViewById(int id) {
if (id < 0) {
return null;
}
return findViewTraversal(id);
}
Run Code Online (Sandbox Code Playgroud)
所以findViewById()只检查id是否有效,如果是,则findViewTraversal()调用protected方法.在View它实现如下:
protected View findViewTraversal(int id) {
if (id == mID) {
return this;
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
它只检查传入的id是否等于id的id,如果是,则View返回this,否则返回null.有趣的部分是findViewTraversal()执行ViewGroup,这个链接导致Android 4.4.4 ViewGroup源代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
这个方法顶部的第一个if与View实现中的相同,只是检查传入的id是否等于id的id,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>
Run Code Online (Sandbox Code Playgroud)
或者,如果它看起来像这样:
<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>
Run Code Online (Sandbox Code Playgroud)
因为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>
Run Code Online (Sandbox Code Playgroud)
想象一下,在这种情况下,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>
Run Code Online (Sandbox Code Playgroud)
并且该布局的性能将优于上面的布局,因为它RelativeLayout在某种程度上在性能方面优于a 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>
Run Code Online (Sandbox Code Playgroud)
而这样的布局肯定会带来巨大的性能提升.
| 归档时间: |
|
| 查看次数: |
6516 次 |
| 最近记录: |