[转载][Android]ListView性能优化之视图缓存(续) – 农民伯伯 – 博客园.
前言
在上一篇ListView性能优化之视图缓存我们讨论了Google I/O中的优化方法,在各个论坛发帖后得到了不错的反馈,诸如:使用ViewHolder技术Tag的问题,利用HashMap自行存储的方案等。这里结合新浪微博中主界面的做法及测试数据与大家进一步探讨。
文章
[Android]ListView性能优化之视图缓存 [本文的上篇]
[Android]ListView性能优化之视图缓存 [JavaEye讨论帖]
正文
一、新浪微博
1.1 截图
(来自网络)
1.2 反编译后相关代码
public View getView( int paramInt, View paramView, ViewGroup paramViewGroup) { int i = --paramInt; int j = - 1 ; if (i == j); for (Object localObject1 = HomeListActivity. this .getReloadView(); ; localObject1 = HomeListActivity. this .getLoadMoreView()) { label26: return localObject1; int k = HomeListActivity. this .mList.size(); int l = paramInt; int i1 = k; if (l != i1) break ; } boolean bool1 = true ; boolean bool2 = null ; String str1; label110: Object localObject2; if (StaticInfo.mUser == null ) { List localList1 = HomeListActivity. this .mList; int i2 = paramInt; str1 = ((MBlog)localList1.get(i2)).uid; List localList2 = HomeListActivity. this .mList; int i3 = paramInt; String str2 = ((MBlog)localList2.get(i3)).uid; String str3 = str1; if (!str2.equals(str3)) break label271; int i4 = 1 ; label156: if (paramView != null ) break label277; HomeListActivity localHomeListActivity1 = HomeListActivity. this ; ListView localListView1 = HomeListActivity. this .mLvHome; List localList3 = HomeListActivity. this .mList; int i5 = paramInt; MBlog localMBlog1 = (MBlog)localList3.get(i5); HomeListActivity localHomeListActivity2 = HomeListActivity. this ; int i6 = paramInt; boolean bool4 = localHomeListActivity2.isNewCommer(i6); int i7 = HomeListActivity. this .mReadMode; localObject2 = new MBlogListItemView(localHomeListActivity1, localListView1, localMBlog1, bool1, bool2, i4, bool4, i7); } while ( true ) { localObject1 = localObject2; break label26: str1 = StaticInfo.mUser.uid; break label110: label271: boolean bool3 = null ; break label156: label277: localObject2 = paramView; try { MainListItemView localMainListItemView = (MainListItemView)localObject2; List localList4 = HomeListActivity. this .mList; int i8 = paramInt; Object localObject3 = localList4.get(i8); HomeListActivity localHomeListActivity3 = HomeListActivity. this ; int i9 = paramInt; boolean bool5 = localHomeListActivity3.isNewCommer(i9); int i10 = HomeListActivity. this .mReadMode; boolean bool6 = bool1; boolean bool7 = bool2; localMainListItemView.update(localObject3, bool6, bool7, bool5, i10); } catch (Exception localException) { HomeListActivity localHomeListActivity4 = HomeListActivity. this ; ListView localListView2 = HomeListActivity. this .mLvHome; List localList5 = HomeListActivity. this .mList; int i11 = paramInt; MBlog localMBlog2 = (MBlog)localList5.get(i11); HomeListActivity localHomeListActivity5 = HomeListActivity. this ; int i12 = paramInt; boolean bool8 = localHomeListActivity5.isNewCommer(i12); int i13 = HomeListActivity. this .mReadMode; localObject2 = new MBlogListItemView(localHomeListActivity4, localListView2, localMBlog2, bool1, bool2, bool3, bool8, i13); } } } |
代码说明:
代码流程已经比较混乱,但是这里能看到并没有直接的inflate,而是自定义了继承自LinearLayout的MBlogListItemView。
public MBlogListItemView(Context paramContext, ListView paramListView, MBlog paramMBlog, boolean paramBoolean1, boolean paramBoolean2, boolean paramBoolean3, boolean paramBoolean4, int paramInt) { super (paramContext); this .context = paramContext; this .parent = paramListView; this .mBlog = paramMBlog; String str1 = paramContext.getCacheDir().getAbsolutePath(); this .mCacheDir = str1; String str2 = paramContext.getFilesDir().getAbsolutePath(); this .mFileDir = str2; ((LayoutInflater)paramContext.getSystemService( "layout_inflater" )).inflate( 2130903061 , this ); TextView localTextView1 = (TextView)findViewById( 2131624016 ); this .mName = localTextView1; TextView localTextView2 = (TextView)findViewById( 2131624041 ); this .mDate = localTextView2; TextView localTextView3 = (TextView)findViewById( 2131624018 ); this .mContent = localTextView3; TextView localTextView4 = (TextView)findViewById( 2131624046 ); this .mSubContent = localTextView4; ImageView localImageView1 = (ImageView)findViewById( 2131624040 ); this .mIconV = localImageView1; ImageView localImageView2 = (ImageView)findViewById( 2131624042 ); this .mIconPic = localImageView2; ImageView localImageView3 = (ImageView)findViewById( 2131624044 ); this .mUploadPic1 = localImageView3; ImageView localImageView4 = (ImageView)findViewById( 2131623979 ); this .mUploadPic2 = localImageView4; TextView localTextView5 = (TextView)findViewById( 2131624047 ); this .tvForm = localTextView5; TextView localTextView6 = (TextView)findViewById( 2131623989 ); this .tvComment = localTextView6; this .tvComment.setOnClickListener( this ); TextView localTextView7 = (TextView)findViewById( 2131623988 ); this .tvRedirect = localTextView7; this .tvRedirect.setOnClickListener( this ); ImageView localImageView5 = (ImageView)findViewById( 2131624049 ); this .imComment = localImageView5; this .imComment.setOnClickListener( this ); ImageView localImageView6 = (ImageView)findViewById( 2131624048 ); this .imRedirect = localImageView6; this .imRedirect.setOnClickListener( this ); ImageView localImageView7 = (ImageView)findViewById( 2131624043 ); this .imGpsIcon = localImageView7; ImageView localImageView8 = (ImageView)findViewById( 2131624013 ); this .mPortrait = localImageView8; LinearLayout localLinearLayout = (LinearLayout)findViewById( 2131624045 ); this .mSubLayout = localLinearLayout; this .mReadMode = paramInt; MBlogListItemView localMBlogListItemView = this ; MBlog localMBlog = paramMBlog; boolean bool1 = paramBoolean1; boolean bool2 = paramBoolean2; boolean bool3 = paramBoolean4; int i = paramInt; localMBlogListItemView.update(localMBlog, bool1, bool2, bool3, i); this .mUploadPic1.setOnClickListener( this ); this .mUploadPic2.setOnClickListener( this ); } |
代码说明:
a). MBlogListItemView extends LinearLayout implements MainListItemView
b). inflate(2130903061,this)这个数字代表R.layout.itemview。
二、测试方案(方案五)
按照新浪微博类似的做法进行测试。
2.1 测试代码
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 开始计时
long startTime = System.nanoTime();
TestItemLayout item;
if (convertView == null) {
item = new TestItemLayout(BaseAdapterActivity.this);
} else
item = (TestItemLayout) convertView;
item.icon1.setImageResource(R.drawable.icon);
item.text1.setText(mData[position]);
item.icon2.setImageResource(R.drawable.icon);
item.text2.setText(mData[position]);
// 停止计时
long endTime = System.nanoTime();
// 计算耗时
long val = (endTime – startTime) / 1000L;
Log.e(“Test”, “Position:” + position + “:” + val);
if (count < 100) {
if (val < 2000L) {
sum += val;
count++;
}
} else
mTV.setText(String.valueOf(sum / 100L) + ":" + nullcount);// 显示统计结果
return item;
}
[/java]
TestItemLayout
[java]
public class TestItemLayout extends LinearLayout {
public TextView text1;
public ImageView icon1;
public TextView text2;
public ImageView icon2;
public TestItemLayout(Context context) {
super(context);
((LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
R.layout.list_item_icon_text, this);
icon1 = (ImageView) findViewById(R.id.icon1);
text1 = (TextView) findViewById(R.id.text1);
icon2 = (ImageView) findViewById(R.id.icon2);
text2 = (TextView) findViewById(R.id.text2);
}
}
[/java]
2.2 测试结果
次数 | 4个子元素 | 10个子元素 |
第一次 | 347 | 460 |
第二次 | 310 | 477 |
第三次 | 324 | 508 |
第四次 | 339 | 492 |
第五次 | 341 | 465 |
三、总结
从测试结果来看与ViewHolder性能非常接近,不会出现tag图片变小的问题(关于图片变小的问题,有朋友说是TAG中的元素对大小和位置有记忆),也能有效的减少findViewById的执行次数,这里建议完全可以取代ViewHolder。
关于ListView内部Adapter的心得大家可以看一下上文的总结4.1。
四、考虑
关于静态内部类这里不是很理解,是否能应用方案五还有待验证。
结束
优化ListView不仅仅只有对convertView的优化,还有许多这样那样的技巧,欢迎大家交流与分享 🙂