[Android]ListView性能优化之视图缓存(续)
正文 一、新浪微博 1.1 截图 1.2 反编译后相关代码 HomeListActivity public ViewgetView( int paramInt,ViewparamView,ViewGroupparamViewGroup) { int i = -- paramInt; int j = - 1 ; if (i == j); for (ObjectlocalObject1 = 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 ; Stringstr1; label110:ObjectlocalObject2; if (StaticInfo.mUser == null ) { ListlocalList1 = HomeListActivity. this .mList; int i2 = paramInt; str1 = ((MBlog)localList1.get(i2)).uid; ListlocalList2 = HomeListActivity. this .mList; int i3 = paramInt; Stringstr2 = ((MBlog)localList2.get(i3)).uid; Stringstr3 = str1; if ( ! str2.equals(str3)) break label271; int i4 = 1 ; label156: if (paramView != null ) break label277; HomeListActivitylocalHomeListActivity1 = HomeListActivity. this ; ListViewlocalListView1 = HomeListActivity. this .mLvHome; ListlocalList3 = HomeListActivity. this .mList; int i5 = paramInt; MBloglocalMBlog1 = (MBlog)localList3.get(i5); HomeListActivitylocalHomeListActivity2 = 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 { MainListItemViewlocalMainListItemView = (MainListItemView)localObject2; ListlocalList4 = HomeListActivity. this .mList; int i8 = paramInt; ObjectlocalObject3 = localList4.get(i8); HomeListActivitylocalHomeListActivity3 = 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 (ExceptionlocalException) { HomeListActivitylocalHomeListActivity4 = HomeListActivity. this ; ListViewlocalListView2 = HomeListActivity. this .mLvHome; ListlocalList5 = HomeListActivity. this .mList; int i11 = paramInt; MBloglocalMBlog2 = (MBlog)localList5.get(i11); HomeListActivitylocalHomeListActivity5 = 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。 MBlogListItemView public MBlogListItemView(ContextparamContext,ListViewparamListView,MBlogparamMBlog, boolean paramBoolean1, boolean paramBoolean2, boolean paramBoolean3, boolean paramBoolean4, int paramInt) { super (paramContext); this .context = paramContext; this .parent = paramListView; this .mBlog = paramMBlog; Stringstr1 = paramContext.getCacheDir().getAbsolutePath(); this .mCacheDir = str1; Stringstr2 = paramContext.getFilesDir().getAbsolutePath(); this .mFileDir = str2; ((LayoutInflater)paramContext.getSystemService( " layout_inflater " )).inflate( 2130903061 , this ); TextViewlocalTextView1 = (TextView)findViewById( 2131624016 ); this .mName = localTextView1; TextViewlocalTextView2 = (TextView)findViewById( 2131624041 ); this .mDate = localTextView2; TextViewlocalTextView3 = (TextView)findViewById( 2131624018 ); this .mContent = localTextView3; TextViewlocalTextView4 = (TextView)findViewById( 2131624046 ); this .mSubContent = localTextView4; ImageViewlocalImageView1 = (ImageView)findViewById( 2131624040 ); this .mIconV = localImageView1; ImageViewlocalImageView2 = (ImageView)findViewById( 2131624042 ); this .mIconPic = localImageView2; ImageViewlocalImageView3 = (ImageView)findViewById( 2131624044 ); this .mUploadPic1 = localImageView3; ImageViewlocalImageView4 = (ImageView)findViewById( 2131623979 ); this .mUploadPic2 = localImageView4; TextViewlocalTextView5 = (TextView)findViewById( 2131624047 ); this .tvForm = localTextView5; TextViewlocalTextView6 = (TextView)findViewById( 2131623989 ); this .tvComment = localTextView6; this .tvComment.setOnClickListener( this ); TextViewlocalTextView7 = (TextView)findViewById( 2131623988 ); this .tvRedirect = localTextView7; this .tvRedirect.setOnClickListener( this ); ImageViewlocalImageView5 = (ImageView)findViewById( 2131624049 ); this .imComment = localImageView5; this .imComment.setOnClickListener( this ); ImageViewlocalImageView6 = (ImageView)findViewById( 2131624048 ); this .imRedirect = localImageView6; this .imRedirect.setOnClickListener( this ); ImageViewlocalImageView7 = (ImageView)findViewById( 2131624043 ); this .imGpsIcon = localImageView7; ImageViewlocalImageView8 = (ImageView)findViewById( 2131624013 ); this .mPortrait = localImageView8; LinearLayoutlocalLinearLayout = (LinearLayout)findViewById( 2131624045 ); this .mSubLayout = localLinearLayout; this .mReadMode = paramInt; MBlogListItemViewlocalMBlogListItemView = this ; MBloglocalMBlog = 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). MBlogListItemViewextendsLinearLayoutimplementsMainListItemView b). inflate( 2130903061,this)这个数字代表R.layout.itemview。 二、测试方案(方案五) 按照新浪微博类似的做法进行测试。 2.1 测试代码 @Override public ViewgetView( int position,ViewconvertView,ViewGroupparent){ // 开始计时 long startTime = System.nanoTime(); TestItemLayoutitem; 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; } TestItemLayout public class TestItemLayout extends LinearLayout{ public TextViewtext1; public ImageViewicon1; public TextViewtext2; public ImageViewicon2; public TestItemLayout(Contextcontext){ 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); } } 2.2 测试结果 次数 4个子元素 10个子元素 第一次 347 460 第二次 310 477 第三次 324 508 第四次 339 492 第五次 341 465 三、总结 从测试结果来看与ViewHolder性能非常接近,不会出现tag图片变小的问题(关于图片变小的问题,有朋友说是TAG中的元素对大小和位置有记忆),也能有效的减少findViewById的执行次数,这里建议完全可以取代ViewHolder。 关于ListView内部Adapter的心得大家可以看一下上文的总结4.1。 四、考虑 关于静态内部类这里不是很理解,是否能应用方案五还有待验证。 五、后期维护 2011-4-29 来自Stony Wang关于Tag的解释: Stony Wang tag的用途应该是仿照delphi的来的,设置一个关联的数据。 简单的说就是,你的UI控件有时候显示的内容带源于(绑定?)某个数据或者对象实例。 当你处理一些事件的时候,不推荐从UI上来重新获取,而是从Tag里面取出来。 举一个例子是,有一个按钮,一开始显示"0",然后每按一次计数增1。 每次click的时候, 1 从btn.getText()再转回Integer 2 从tag里面把之前设好的Integer拿出来,加一,再settag? 如果觉得1和2区别不大的话,那么如果显示的内容不是"0",而是"已经点了0次"呢? 更新UI的时候,可以将关联的对象放到tag里面,在处理相关触发事件的时候,可以方便的获取原始的数据。 ListView的Tag用法也不算很错,而是用的时候没有注意设置的时候要注意“对称”。 Tag本身可以理解成放ViewHolder,那么和ViewHolder的加速只不过是存放的位置不同,加速效果基本一致。 “对称”我所指的内容是: 不管你要显示的数据的逻辑是如何的,如果你设置了某个View的宽度,那么在任何一种数据的填充UI逻辑里面,不可以有不设置这个View宽度的代码路径。 简单的例子就是,我根据某个布尔值,如果是false的话,将ImageView设置为View.INVISIBLE if ( item.isHidden()){ mImage.setVisibility(View.INVISIBLE); } 这样是错误的,因为如果这里缓存的UI控件的状态会被复用到其它item上,而这个item恰巧可能是需要显示的。 必须补上else语句 else{ mImage.setVisibility(View.VISIBLE); } 这个估计就是那位仁兄拖动图片变小的原因了。 最后说一下,ListView控件条目部分,一共产生的条目是屏幕能容纳的数目+2(还是+1?我记不清楚了),然后循环使用。 结束 优化ListView不仅仅只有对convertView的优化,还有许多这样那样的技巧,欢迎大家交流与分享 :) 本文转自over140 51CTO博客,原文链接:http://blog.51cto.com/over140/582135,如需转载请自行联系原作者