[Android]ListView性能优化之视图缓存(续)

简介:

一、新浪微博

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

      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?我记不清楚了),然后循环使用。

 本文转自博客园农民伯伯的博客,原文链接:[Android]ListView性能优化之视图缓存(续),如需转载请自行联系原博主。

目录
相关文章
|
11月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
1014 4
|
5月前
|
数据库 Android开发
Android使用EditText+Listview实现搜索效果(使用room模糊查询)
本文介绍如何在Android中使用EditText与ListView实现搜索功能,并结合Room数据库完成模糊查询。主要内容包括:Room的模糊查询语句(使用`||`代替`+`号)、布局美化(如去除ListView分割线和EditText下划线)、EditText回车事件监听,以及查询逻辑代码示例。此外,还提供了相关扩展文章链接,帮助读者深入了解ListView优化、动态搜索及Room基础操作。
334 65
|
4月前
|
缓存 负载均衡 网络协议
电商API接口性能优化技术揭秘:缓存策略与负载均衡详解
电商API接口性能优化是提升系统稳定性和用户体验的关键。本文聚焦缓存策略与负载均衡两大核心,详解其在电商业务中的实践。缓存策略涵盖本地、分布式及CDN缓存,通过全量或部分缓存设计和一致性维护,减少后端压力;负载均衡则利用反向代理、DNS轮询等技术,结合动态调整与冗余部署,提高吞吐量与可用性。文中引用大型及跨境电商平台案例,展示优化效果,强调持续监控与迭代的重要性,为电商企业提供了切实可行的性能优化路径。
|
11月前
|
缓存 前端开发 Android开发
安卓开发中的自定义视图:从零到英雄
【10月更文挑战第42天】 在安卓的世界里,自定义视图是一块画布,让开发者能够绘制出独一无二的界面体验。本文将带你走进自定义视图的大门,通过深入浅出的方式,让你从零基础到能够独立设计并实现复杂的自定义组件。我们将探索自定义视图的核心概念、实现步骤,以及如何优化你的视图以提高性能和兼容性。准备好了吗?让我们开始这段创造性的旅程吧!
157 1
|
12月前
|
算法 数据处理 Android开发
掌握安卓性能优化的秘诀:电池寿命与运行效率的提升
【10月更文挑战第6天】 本文深入探讨了安卓应用开发中的性能优化技巧,重点分析了影响电池寿命和运行效率的关键因素,并提供了针对性的优化策略。通过代码优化、资源管理、后台任务处理等方法,开发者可以显著提升应用的续航能力和流畅度。同时,结合具体案例,展示了如何在实际开发中应用这些技巧,确保应用在各种场景下都能保持高效运行。本文旨在为安卓开发者提供实用的性能优化指导,助力其打造更优质的应用体验。
298 2
|
12月前
|
Android开发 开发者
安卓应用开发中的自定义视图
【9月更文挑战第37天】在安卓开发的海洋中,自定义视图犹如一座座小岛,等待着勇敢的探索者去发现其独特之处。本文将带领你踏上这段旅程,从浅滩走向深海,逐步揭开自定义视图的神秘面纱。
93 3
|
7月前
|
存储 缓存 NoSQL
Redis缓存设计与性能优化
Redis缓存设计与性能优化涵盖缓存穿透、击穿、雪崩及热点key重建等问题。针对缓存穿透,可采用缓存空对象或布隆过滤器;缓存击穿通过随机设置过期时间避免集中失效;缓存雪崩需确保高可用性并使用限流熔断组件;热点key重建利用互斥锁防止大量线程同时操作。此外,开发规范强调键值设计、命令使用和客户端配置优化,如避免bigkey、合理使用批量操作和连接池管理。系统内核参数如vm.swappiness、vm.overcommit_memory及文件句柄数的优化也至关重要。慢查询日志帮助监控性能瓶颈。
242 9
|
10月前
|
网络协议 Linux Android开发
深入探索Android系统架构与性能优化
本文旨在为读者提供一个全面的视角,以理解Android系统的架构及其关键组件。我们将探讨Android的发展历程、核心特性以及如何通过有效的策略来提升应用的性能和用户体验。本文不包含常规的技术细节,而是聚焦于系统架构层面的深入分析,以及针对开发者的实际优化建议。
283 21
|
11月前
|
Android开发 开发者
Android性能优化——内存管理的艺术
Android性能优化——内存管理的艺术
|
11月前
|
搜索推荐 前端开发 Android开发
安卓应用开发中的自定义视图实现
【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
132 4

热门文章

最新文章