Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 559|回复: 0

ListView中getView的原理与解决多轮重复调用的方法

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-21 09:06:46 | 显示全部楼层 |阅读模式

    以下文章内容来自网络复制粘贴,由于是之前整理到笔记本的部分找不到出处。如有侵犯,敬请告知。


     

    【0】ListView中getView的工作原理:

    [1]ListView asks adapter “give me a view” (getView) for each item of the list.(通过getView来获取每个item)

    [2]A new View is returned and displayed(获取到后返回显示)

    那么如果我们有大量的数据需要显示的时候,每个Item都去重复执行getView中的创建新的View的动作吗?这样做会耗费大量的资源去执行重复的事情,实际上Android为我们提供了一套重复利用的机制叫做Recycler”:

    原理简单描述下就是这样:

    在一个完整的ListView第一次出现时,每个Item都是Null的,getView的时候会跑到需要inflate一个Item的代码段,假设整个view只能最多显示10个item,那么当滑动到第11个Item的时候,第一个item会放入“recycler”,如果第11个Item和放入“Recycler”的item的view一致,那么就会使用"Recycler"里面的Item来显示,从而不用再重复inflate一次,这样大大节省了创建View的工作,在需要显示大量数据时显得尤为重要。

    工作原理的示意图如下:


    学习自http://android.amberfog.com/?p=296

    Demo:

    这是一个getView的方法,其他细节的Code就不显示了

     

    1. static class ViewHolder   
    2.     {  
    3.         public ImageView localImageView = null;  
    4.         public TextView localTextView1 = null;  
    5.         public TextView localTextView2 = null;  
    6.         public TextView localTextView3 = null;  
    7.     }  
    8.       
    9.     public View getView(int paramInt, View paramView, ViewGroup paramViewGroup)  
    10.     {  
    11.         logger.i("This is position:" + paramInt);  
    12.         WrapperSonglist localUserShareSonglistEntity = (WrapperSonglist) getItem(paramInt);  
    13.         if(localUserShareSonglistEntity != null)  
    14.         {  
    15.             ViewHolder holder = null;  
    16.             if(paramView == null)  
    17.             {  
    18.                 this.logger.d("convertView == null,Then inflate and findViewById");  
    19.                 paramView = this.mInflater.inflate(R.layout.listitem04, paramViewGroup, false);  
    20.                 holder = new ViewHolder();  
    21.                 holder.localImageView = (ImageView) paramView.findViewById(R.id.listitem04ImageView);  
    22.                 holder.localTextView1 = (TextView) paramView.findViewById(R.id.listitem04TextView01);  
    23.                 holder.localTextView2 = (TextView) paramView.findViewById(R.id.listitem04TextView02);  
    24.                 holder.localTextView3 = (TextView) paramView.findViewById(R.id.listitem04TextView03);  
    25.                 paramView.setTag(holder);  
    26.             }  
    27.             else  
    28.             {  
    29.                 //Used ViewHolder to improve performance  
    30.                 this.logger.d("convertView != null,Then findViewById(get Holder)");  
    31.                 holder = (ViewHolder) paramView.getTag();  
    32.             }  
    33.             if(paramView != null)  
    34.             {  
    35.                 this.logger.d("convertView != null,Then SetValue");  
    36.                   
    37.                 String mstr = localUserShareSonglistEntity.getSonglistImage();  
    38.                 int id = localUserShareSonglistEntity.getSonglistId();  
    39.                 holder.localTextView1.setText("[id]:"+id+",bitmap:url:"+mstr);  
    40.                   
    41.                 String name = localUserShareSonglistEntity.getSonglistName();  
    42.                 holder.localTextView2.setText("[Name]:"+name);  
    43.                   
    44.                 String url = localUserShareSonglistEntity.getSonglistUrl();  
    45.                 holder.localTextView3.setText("[Url]:"+url);  
    46.             }  
    47.         }  
    48.         return paramView;  
    49.     }  

     

     

    当我们第一次启动到Listview的时候如下,只显示了5个Item,那么getView被调用5次:

     


    打印的Log如下:可以看到从0-4都是null,我们需要做inflate的动作,

     

    1. 01-12 17:58:22.144: ERROR/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:69 getView ] - This is position:0  
    2. 01-12 17:58:22.154: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:80 getView ] - convertView == null,Then inflate and findViewById  
    3. 01-12 17:58:22.174: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:98 getView ] - convertView != null,Then SetValue  
    4. 01-12 17:58:22.174: ERROR/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:69 getView ] - This is position:1  
    5. 01-12 17:58:22.174: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:80 getView ] - convertView == null,Then inflate and findViewById  
    6. 01-12 17:58:22.184: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:98 getView ] - convertView != null,Then SetValue  
    7. 01-12 17:58:22.184: ERROR/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:69 getView ] - This is position:2  
    8. 01-12 17:58:22.184: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:80 getView ] - convertView == null,Then inflate and findViewById  
    9. 01-12 17:58:22.194: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:98 getView ] - convertView != null,Then SetValue  
    10. 01-12 17:58:22.194: ERROR/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:69 getView ] - This is position:3  
    11. 01-12 17:58:22.194: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:80 getView ] - convertView == null,Then inflate and findViewById  
    12. 01-12 17:58:22.204: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:98 getView ] - convertView != null,Then SetValue  
    13. 01-12 17:58:22.204: ERROR/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:69 getView ] - This is position:4  
    14. 01-12 17:58:22.204: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:80 getView ] - convertView == null,Then inflate and findViewById  
    15. 01-12 17:58:22.214: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:98 getView ] - convertView != null,Then SetValue<strong>  
    16. </strong>  


    当我们小心往下滑动一个位置,刚出现第6个Item,此时第1个还没有消失时,

     


    这个时候只打印了一个获取第6个Item的Log,如下:可以看到第6个Item还是为null,需要inflate出来新的

     

    1. 01-12 18:02:37.623: ERROR/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:69 getView ] - This is position:5  
    2. 01-12 18:02:37.623: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:80 getView ] - convertView == null,Then inflate and findViewById  
    3. 01-12 18:02:37.633: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:98 getView ] - convertView != null,Then SetValue<strong>  
    4. </strong>  


    如果此时再往下滑动列表,第1个item此时会放入Recycler,第7个Item此时不再是null,而是利用了第1个item的View,如下:

     


    从下面的Log,可以看到从第7个开始就不是null了

    01-12 18:52:36.243: ERROR/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:69 getView ] - This is position:6

    01-12 18:52:36.243: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:89 getView ] - convertView != null,Then findViewById
    01-12 18:52:36.243: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:98 getView ] - convertView != null,Then SetValue
    01-12 18:52:36.693: ERROR/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:69 getView ] - This is position:7
    01-12 18:52:36.693: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:89 getView ] - convertView != null,Then findViewById
    01-12 18:52:36.693: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:98 getView ] - convertView != null,Then SetValue
    01-12 18:52:37.024: ERROR/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:69 getView ] - This is position:8
    01-12 18:52:37.024: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:89 getView ] - convertView != null,Then findViewById
    01-12 18:52:37.034: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:98 getView ] - convertView != null,Then SetValue
    01-12 18:52:37.604: ERROR/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:69 getView ] - This is position:9
    01-12 18:52:37.604: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:89 getView ] - convertView != null,Then findViewById
    01-12 18:52:37.604: DEBUG/MusicDemo(1272): @kesen@ [ main: Activity4Adapter.java:98 getView ] - convertView != null,Then SetValue

    等所有的item,一共10个都显示之后,不管上下滑动都再也不是NULL了,说明这个时候都是使用Recycle里面的view,而不会再重新inflate了,显然这样节省很多重复的操作

    【1】重复多轮调用getView的解决方案

    当我们在使用listview的时候。有时候自定义adapter的时候,是不是会发现在getview里打印日志的时候,重复调用很多次?有时候4次。有的严重甚至到10次,当我们在listview中移动的时候。每移动一列都会调用很多次,这样大大影响到效率!其实这和listview本身在android上的机制有关。下面我开始来介绍一下吧:

          在布局,我们只有一个listview的时候。那好。我们把高设置成wrap_content的时候。在listview里加载几行看看。日志在getview里打印一下。是不是重复调用了?那这个办法就好弄了。把高设置成fill_parent就成了。这个时候发现日志还是重复调用?那就要看一下Listview的上一级而已的高是不是也是设置也fill_parent的,如果不是。请改动吧。如果是。。。那我还真没碰到重复调用的!因为测试好几次了!

         如果我们在而已里不只一个Listview。一个复杂好看的布局可能有很多。listview在布局的某个地方。这个时候有时候运气不好。你会发现你调用了很多次getview。我测试的时候。最高230次。。。可想而知。这个速度是相当慢。而且每移动一次就是调用这么多次!对于这样的情况,在修改布局的时候,要考虑以下两点:1.首先考虑需求布局和性能哪个更重要一点。2.考虑listview周边哪个布局控件影响到了它!

         如果在性能上没有太大影响,而需求要求必需是那样的布局。那就以布局为主。看看有没有别的方法来优化一下listview,当然前提是布局一点都不能调整。如果能调整,布局没有太大变动。而listview又能很好的优化。那就当然优化了!当我们优化的时候。首先要看一下有没有影响到Listview重绘的控件,比如。如果它上面和下面都有控件。而且高都是wrap_content,那么你就要设置成fill_parent或者固定高。这样listview在高上就不会重绘,这是最主要的一点。那左右是不是也有控件(一般一个手机页面用到list的时候不会有这么多控件)?有,那我们就也要调整,那就同高一样的设置。一定要让listview是一个固定在那个地方不动的。不然,你就等着让他重复去调用吧!

         其实说了这么多。最主要的还是在我们进行布局的时候。要巧妙的运用每个控件的属性,以及了解控件每个的原理。这样在我们进行UI设计的时候,才能很好的去结合!

     

     
     
    全文完
    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-1-12 15:48 , Processed in 0.065521 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表