findViewById,ViewHolder,SparseArray<View> viewHolder原理以及效率对比

1.SparseArray<View> viewHolder

 SparseArray 这个集合而不是 HashMap ,我们知道 SparseArray 是Android的一个工具类,是官方推荐用来代替 HashMap<Integer,E> 的一个类,它的内部采用了二分查找的实现提高了查找效率。
--用二分法查找到引用。
public class ViewHolderUtil {
    public static <T extends View> T get(View convertView, int id) {
        SparseArray<View> viewHolder = (SparseArray<View>) convertView.getTag();
        if (viewHolder == null) {
            viewHolder = new SparseArray<View>();
            convertView.setTag(viewHolder);
        }
        View childView = viewHolder.get(id);
        if (childView == null) {
            childView = convertView.findViewById(id);
            viewHolder.put(id, childView);
        }
        return (T) childView;
    }
}
 
 
/**
 * Gets the Object mapped from the specified key, or the specified Object
 * if no such mapping has been made.
 */
@SuppressWarnings("unchecked")
public E get(int key, E valueIfKeyNotFound) {
    int i = ContainerHelpers.binarySearch(mKeys, mSize, key);

    if (i < 0 || mValues[i] == DELETED) {
        return valueIfKeyNotFound;
    } else {
        return (E) mValues[i];
    }
}
2.findViewById
VIew
protected View findViewTraversal(@IdRes int id) {
    if (id == mID) {
        return this;
    }
    return null;
}
 
 
ViewGroup
protected View findViewTraversal(@IdRes 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;
}
可见采用的是 遍历数组,从而查找到引用
3.ViewHolder
直接就持有引用,不需要查找
 
 
 
 
 
 
So,使用ViewHolder应该是最快的,SparseArray次之。really?做一下实验。
 
 
1.先看简单的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:text="标题"
        android:textSize="20sp"
        android:id="@+id/title"
        android:layout_height="wrap_content"/>
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="2dp"
        android:background="#000"
        android:layout_height="match_parent"/>
    <TextView
        android:layout_width="wrap_content"
        android:text="内容"
        android:id="@+id/content"
        android:layout_height="wrap_content"/>
</LinearLayout>
代码
public void onClick(View v) {
    long begin;
    long duration;
    switch (v.getId()) {
        case R.id.btn_findviewbyid:
            begin = System.currentTimeMillis();
            doFindViewById();
            duration = System.currentTimeMillis() - begin;
            LogUtils.LOG("btn_findviewbyid" + duration);
            tv_findviewbyid.setText("time:" + duration);
            break;
        case R.id.btn_sparsearray:
            begin = System.currentTimeMillis();
            doSparsearray();
            duration = System.currentTimeMillis() - begin;
            LogUtils.LOG("btn_sparsearray" + duration);
            tv_sparsearray.setText("time:" + duration);
            break;
        case R.id.btn_viewholder:
            begin = System.currentTimeMillis();
            doViewHolder();
            duration = System.currentTimeMillis() - begin;
            LogUtils.LOG("btn_viewholder" + duration);
            tv_viewholder.setText("time:" + duration);

            break;
    }
}
 
 
private void doSparsearray() {
    View view = View.inflate(this, R.layout.item_joke, null);
    for (int i = 0; i < COUNT; i++) {
        TextView title = ViewHolderUtil.get(view, R.id.title);
        TextView content = ViewHolderUtil.get(view, R.id.content);
        ImageView imageView = ViewHolderUtil.get(view, R.id.imageView);
        title.setText("title");
        content.setText("content");
    }
}

private void doFindViewById() {
    View view = View.inflate(this, R.layout.item_joke, null);
    for (int i = 0; i < COUNT; i++) {

        TextView title = (TextView) view.findViewById(R.id.title);
        ImageView imageView = (ImageView) view.findViewById(R.id.imageView);
        TextView content = (TextView) view.findViewById(R.id.content);
        title.setText("title");
        content.setText("content");
    }
}

private void doViewHolder() {
    View view = View.inflate(this, R.layout.item_joke, null);
    ViewHolder viewHolder = new ViewHolder();
    viewHolder.title = (TextView) view.findViewById(R.id.title);
    viewHolder.imageView = (ImageView) view.findViewById(R.id.imageView);
    viewHolder.content = (TextView) view.findViewById(R.id.content);
    for (int i = 0; i < COUNT; i++) {
        viewHolder.title.setText("title");
        viewHolder.content.setText("content");
        ImageView imageView = viewHolder.imageView;
    }
}
 
 
时间,count 为 10W次:
如果说设置数据的时间(setText)为1088,那么 稀疏数组 查找略快 大概254ms,findviewbyid 大概 400ms
06-23 10:17:53.458 21070-21070/com.example.testeveryting I/CnfolCms: btn_sparsearray1342

06-23 10:17:58.433 21070-21070/com.example.testeveryting I/CnfolCms: btn_findviewbyid1486

06-23 10:18:01.673 21070-21070/com.example.testeveryting I/CnfolCms: btn_viewholder1088

2.看复杂一点的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:orientation="vertical">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="标题"
            android:textSize="20sp"/>

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="2dp"
            android:layout_height="match_parent"
            android:background="#000"/>

        <TextView
            android:id="@+id/content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="内容"/>

    </LinearLayout>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:orientation="vertical">

        <TextView
            android:id="@+id/title1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="标题"
            android:textSize="20sp"/>

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="2dp"
            android:layout_height="match_parent"
            android:background="#000"/>

        <TextView
            android:id="@+id/content1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="内容"/>

    </LinearLayout>

</LinearLayout>
 
 
06-23 11:09:09.083 10863-10863/com.example.testeveryting I/CnfolCms: btn_sparsearray2558

06-23 11:09:31.258 10863-10863/com.example.testeveryting I/CnfolCms: btn_findviewbyid3630

06-23 11:09:36.248 10863-10863/com.example.testeveryting I/CnfolCms: btn_viewholder2193

 
 
如果说设置数据的时间(setText)为2193,那么 稀疏数组 查找略快 大概365ms,findviewbyid 大概 1437ms
 
 
 
 
 
 
可见,android 4.4.4 mx3手机:布局简单(例如1)的情况下,稀疏数组时间大约是findviewbyid的60%。
     略复杂一点(例如2),稀疏数组时间大约是findviewbyid的25%。在复杂 布局 情况下 节约的时间还是挺可观的。
 
 
然而换了一部手机 sansumg s7 android6.0 结果却 很奇怪。 findviewbyid反而时间(例子2)略少。
 
 
06-23 11:21:06.546 11228-11228/com.example.testeveryting I/CnfolCms: btn_sparsearray797

06-23 11:21:07.936 11228-11228/com.example.testeveryting I/CnfolCms: btn_findviewbyid794

06-23 11:21:09.616 11228-11228/com.example.testeveryting I/CnfolCms: btn_viewholder682
推测是,计算能力大幅提升的s7 查找时间很快,反而 sparsearray的创建对象的时间 成为了瓶颈(findviewbyid没有创建对象),因此sparseArray查找上节约的一点时间反而被创建对象所需的时间所抵消。
 
 
 
 
 
 
所以,综上,sparseArray在布局复杂需要大量查找的情况下确实能节约很多查找时间,但是可能会因此增加了 创建对象的时间,尤其是在高配置的手机上。
因此为了适配高中低端手机。我觉得最好还是直接使用viewholder,其次sparseArray。
以上实验可能有问题,欢迎指正。
 
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值