通过Adapter为AbslistView提供内容是一个常见的做法:在ListView或者GridView的Adapter中的getView()方法中,加入一行日志,看getView()被调用的情况

  1. public View getView(int position, View convertView, ViewGroup parent) {
  2. Log.d('cube_list',
  3. String.format("getView %s, %s", position, convertView == null));
  4. // 创建
  5. if (convertView == null) {
  6. }
  7. // 复用
  8. else {
  9. }
  10. }

问题表现

对于ListView,我们使用如下的一个xml文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" >
  5. <ListView
  6. android:id="@+id/ly_image_list_small"
  7. android:layout_width="wrap_content"
  8. android:layout_height="wrap_content"
  9. android:divider="@null"
  10. android:fadingEdge="none"
  11. android:listSelector="@android:color/transparent"
  12. android:padding="10dp"
  13. android:scrollbarStyle="outsideOverlay" />
  14. </RelativeLayout>

getView 方法返回的view含有一个网络图片,下载完成后,会导致重新绘制。

运行程序,在Logcat中 有可能 会看到getView
0
会被打印出很多条。

  1. 03-15 14:32:41.980 cube_list getView 0, true
  2. 03-15 14:32:41.980 cube_list getView 1, false
  3. 03-15 14:32:41.980 cube_list getView 2, false
  4. 03-15 14:32:41.990 cube_list getView 3, false
  5. 03-15 14:32:41.990 cube_list getView 4, false
  6. 03-15 14:32:41.990 cube_list getView 0, false
  7. 03-15 14:32:41.990 cube_list getView 1, false
  8. 03-15 14:32:41.990 cube_list getView 2, false
  9. 03-15 14:32:41.990 cube_list getView 3, false
  10. 03-15 14:32:41.990 cube_list getView 4, false
  11. 03-15 14:32:42.000 cube_list getView 0, false
  12. 03-15 14:32:42.010 cube_list getView 1, true
  13. 03-15 14:32:42.010 cube_list getView 2, true
  14. 03-15 14:32:42.010 cube_list getView 3, true
  15. 03-15 14:32:42.020 cube_list getView 4, true

第一页之后,第0项不再被绘制,但GridView 情况却糟糕多了, 滑动的过程,第0项还在不停被绘制。


原因分析

起因:类似这样的情况,都是加入了列表项之后,列表项自身的一些操作,比如加入图片,导致整个view重新绘制。在重新绘制的过程中,onMeasure方法会创建出列表项来确定大小。

ListView

onMeasure()时:

  1. 如果宽度或者高度的状态为 UNSPECIFIED, 会多次绘制列表首项,直到大小确定为止。
  2. 如果高度的状态为AT_MOST, 会绘制多个列表项进行确定大小。

主要代码如下:

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  2. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  3. int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  4. int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  5. // ViewMode 处于UNSPECIFIED 状态,绘制首项来确定大小
  6. mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
  7. if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED
  8. || heightMode == MeasureSpec.UNSPECIFIED)) {
  9. // getView(0)
  10. final View child = obtainView(0, mIsScrap);
  11. // other code
  12. }
  13. }
  14. // other code
  15. // AT_MOST 状态,绘制多个列表项以确定高度。
  16. if (heightMode == MeasureSpec.AT_MOST) {
  17. // 会调用多个getView,这些view将不会被复用
  18. heightSize = measureHeightOfChildren(widthMeasureSpec, 0,
  19. NO_POSITION, heightSize, -1);
  20. }
  21. // other code
  22. }

解决方案:

如果ListView大小未决,则会绘制列表项,以确定自身大小。让ListView大小处于EXACTLY状态即可。

根据 Android中View大小的确定过程,所描述:

  1. 如果ListView父容器大小确定,设置尺寸为 match_parent 不会出现此问题。
  2. 不管父容器什么状态,ListView大小为确定数值不会出现此问题。

GirdView

GridView看起来比较无解,每次onMeasure()都会导致列表首项被绘制。

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  2. // other code
  3. mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
  4. final int count = mItemCount;
  5. if (count > 0) {
  6. final View child = obtainView(0, mIsScrap);
  7. // ...
  8. }
  9. // ...
  10. }

只要重新确定大小,首项就一定会被重绘,这个是非常险恶的。从onMeasure的实现来看,几乎无法避免,只能从业务方入手。

  1. 如果是类似九宫格的应用场景,这里有一个解决方案。Gridview的错误用法及替代方案

  2. 一定有翻屏的需求,可用ListView代替。

  3. 釜底抽薪,让列表项不要求重绘。

ListView / GirdView Adpater的getView方法,首项多次调用的更多相关文章

  1. ListView的adapter中getView方法一直调用

    当ListView的高度不定(比如重写ListView搞成可自己主动的扩展的ListView)或 ListView嵌套在SrollView(高度不定)中,listView中的一个item元素改变会使得 ...

  2. [Android]ListView的Adapter.getView()方法中延迟加载图片的优化

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4139998.html 举个例子吧,以好友列表为例 ListVi ...

  3. Android LIstView初次创建getview方法执行多次问题

    写listview优化的时候,发现Listview初次创建的时候会多次执行getView方法. <?xml version="1.0" encoding="utf- ...

  4. android ListView 多次调用 getView方法

    <ListView            android:layout_width="match_parent"            android:layout_heig ...

  5. Android ListView getView()方法重复调用导致position错位

    问题现状:Android ListView getView()方法重复调用导致position错位 解决办法:把ListView布局文件的layout_height属性改为fill_parent或者m ...

  6. [Android]在Adapter的getView方法中绑定OnClickListener比较好的方法

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4146512.html  给ListView中每个item绑定点 ...

  7. 自定义adapter 的getView方法被重复执行了n次的解决方法

    1. getView执行的次数和你的getCount没有直接的关系   ,getCount和你listView里面的条目数量(行数量)有关系 ,getView方法执行次数取决于你屏幕上显示几个条目,比 ...

  8. [转]Android Adapter以及getView()方法的理解

    Android Adapter基本理解: 我的理解是: 1.一个有许多getter的类(就是getView(),getCount()....这些方法) 2.有多少个get方法?都是什么? 这些gett ...

  9. BaseAdapter的getView()方法

    getView()是BaseAdapter的一个重要方法.为了研究getView()方法,使用了以下的类. // apk列表 class list_apk extends BaseAdapter{ p ...

随机推荐

  1. HTML的发展历史

    HTML是Web统一语言,这些容纳在尖括号里的简单标签,构成了如今的Web,1991年,Tim Berners-Lee编写了一份叫做“HTML标签”的文档,里面包含了大约20个用来标记网页的HTML标 ...

  2. TypeScript算法与数据结构-栈篇

    本文的源码在这里,可以参考一下 栈也是一种使用非常广泛的线性数据结构,它具有后进先出last in first out的特点.通俗的例子就像我们平时一本一本的往上放书,等到我们又想用书时,我们首先接触 ...

  3. 【已解决】极速迅雷win10闪退解决方案

    [已解决]极速迅雷win10闪退解决方案 本文作者:天析 作者邮箱:2200475850@qq.com 发布时间: Wed, 17 Jul 2019 18:01:00 +0800 在吾爱下载了个极速迅 ...

  4. 虚拟机安装master,克隆slave0、slave1(多台机相连,网络匹配)

    1.在虚拟机中创建一个名叫master的主机 2.创建成功后,打开编辑选项——虚拟网络网络编辑器,填网关 3.打开终端,进入root权限,编写命令 设置虚拟机DNS 4.给master网络配置好后,克 ...

  5. linux防火墙(一)

    安全技术 入侵检测与管理系统IDS(Intrusion Detection Systems):特点是不阻断任何网络访问,量化.定位来自内外网络的威胁情况,主要以提供报告和事后监督为主,提供有针对性的指 ...

  6. Yum三方仓库——EPEL

    参考:什么是EPEL 及 Centos上安装EPEL 参考:How to Enable EPEL Repository for RHEL/CentOS 7.x/6.x/5.x 前言 RHEL以及他的衍 ...

  7. IDEA实用教程(四)—— 创建JavaSE工程

    三. 创建JavaSE工程 第一步 第二步 第三步 第四步 第五步 第六步 运行代码.右键选中图中按钮 选择Run

  8. about微信小程序

    1.<text>文本标签</text> ps:只有用text包裹的文字才能在微信里长按选中 2.单位 px变成rpx rpx是逻辑分变率     px=2rpx, rpx可以实 ...

  9. python3 wordcloud词云

    wordclou:根据文本生成词云 一.词云设置 wc=WordCloud(width=400, height=200, #画布长.宽,默认(400,200)像素 margin=1, #字与字之间的距 ...

  10. Select count(*)和Count(1)的区别和执行方式

    在SQL Server中Count(*)或者Count(1)或者Count([列])或许是最常用的聚合函数.很多人其实对这三者之间是区分不清的.本文会阐述这三者的作用,关系以及背后的原理. 往常我经常 ...