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。
以上实验可能有问题,欢迎指正。