zoukankan      html  css  js  c++  java
  • [Android]ListView性能优化之视图缓存(续)


    前言

      在上一篇ListView性能优化之视图缓存我们讨论了Google I/O中的优化方法,在各个论坛发帖后得到了不错的反馈,诸如:使用ViewHolder技术Tag的问题,利用HashMap自行存储的方案等。这里结合新浪微博中主界面的做法及测试数据与大家进一步探讨。

    声明

      欢迎转载,但请保留文章原始出处:)

        博客园:http://www.cnblogs.com

        农民伯伯: http://over140.cnblogs.com 

    文章

      [Android]ListView性能优化之视图缓存 [本文的上篇]

      [Android]ListView性能优化之视图缓存 [JavaEye讨论帖]

    正文

      一、新浪微博

        1.1  截图

          (来自网络)

        1.2  反编译后相关代码

          HomeListActivity

        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。

          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(2130903061this);
        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;
            }

          TestItemLayout

    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);
        }
    }

        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的优化,还有许多这样那样的技巧,欢迎大家交流与分享 :)

  • 相关阅读:
    Openstack CloudKitty 计量计费命令行操作
    $out表单提交转成数组
    AddWhere
    正则
    全选反选
    showErr()
    模拟登陆
    MYSQL添加权限
    三元相位符
    打开ci 调试
  • 原文地址:https://www.cnblogs.com/over140/p/2006615.html
Copyright © 2011-2022 走看看