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

  • 相关阅读:
    Saltstack module apache 详解
    Saltstack module ip 详解
    Saltstack module iosconfig 详解
    Saltstack module introspect 详解
    Saltstack module inspector 详解
    Saltstack module ini 详解
    Saltstack module incron 详解
    Modbus 指令 RS485指令规则
    停车系统对接第三方在线支付平台(二)
    停车系统对接第三方在线支付平台
  • 原文地址:https://www.cnblogs.com/over140/p/2006615.html
Copyright © 2011-2022 走看看