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

public View getView(int position, View convertView, ViewGroup parent) {
Log.d('cube_list',
String.format("getView %s, %s", position, convertView == null));
// 创建
if (convertView == null) { }
// 复用
else {
}
}

问题表现

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

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" > <ListView
android:id="@+id/ly_image_list_small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:divider="@null"
android:fadingEdge="none"
android:listSelector="@android:color/transparent"
android:padding="10dp"
android:scrollbarStyle="outsideOverlay" /> </RelativeLayout>

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

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

03-15 14:32:41.980    cube_list﹕ getView 0, true
03-15 14:32:41.980 cube_list﹕ getView 1, false
03-15 14:32:41.980 cube_list﹕ getView 2, false
03-15 14:32:41.990 cube_list﹕ getView 3, false
03-15 14:32:41.990 cube_list﹕ getView 4, false
03-15 14:32:41.990 cube_list﹕ getView 0, false
03-15 14:32:41.990 cube_list﹕ getView 1, false
03-15 14:32:41.990 cube_list﹕ getView 2, false
03-15 14:32:41.990 cube_list﹕ getView 3, false
03-15 14:32:41.990 cube_list﹕ getView 4, false
03-15 14:32:42.000 cube_list﹕ getView 0, false
03-15 14:32:42.010 cube_list﹕ getView 1, true
03-15 14:32:42.010 cube_list﹕ getView 2, true
03-15 14:32:42.010 cube_list﹕ getView 3, true
03-15 14:32:42.020 cube_list﹕ getView 4, true

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


原因分析

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

ListView

onMeasure()时:

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

主要代码如下:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec); // ViewMode 处于UNSPECIFIED 状态,绘制首项来确定大小
mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED
|| heightMode == MeasureSpec.UNSPECIFIED)) { // getView(0)
final View child = obtainView(0, mIsScrap); // other code
}
} // other code // AT_MOST 状态,绘制多个列表项以确定高度。
if (heightMode == MeasureSpec.AT_MOST) { // 会调用多个getView,这些view将不会被复用
heightSize = measureHeightOfChildren(widthMeasureSpec, 0,
NO_POSITION, heightSize, -1);
} // other code
}

解决方案:

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

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

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

GirdView

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

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    // other code

    mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
final int count = mItemCount;
if (count > 0) { final View child = obtainView(0, mIsScrap); // ...
} // ...
}

只要重新确定大小,首项就一定会被重绘,这个是非常险恶的。从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. 解决JAVA连接Sybase数据库查询数据乱码的问题

    连接字符串加上charset=eucgb&jconnect_version=0例如:jdbc:sybase:Tds:server:port/database?charset=eucgb& ...

  2. Linux开机自动启动服务

    当我们的Linux,关机后,或者重启后,有些服务需要人工启动才能有.为了解决这个问题,我找了一个办法,用一个脚本,开机启动想启动的服务. 方法一:(强烈推荐) 1.写一个脚本auto.sh vim  ...

  3. c# 抽象工厂设计模式

  4. php 图片与base64互转

    header('Content-type:text/html;charset=utf-8'); //读取图片文件,转换成base64编码格式 $image_file = '1.png'; $image ...

  5. 【HCIA Gauss】学习汇总-数据库管理(数据库设计 范式 索引 分区)-7

    zsql user/pasword@ip:port -c "show databases" # 展示一条sql语句 spool file_path 指定输出文件 可以为相对路径 s ...

  6. 基于beautifulSoup进行电影网站排名的获取与格式化输出

    要求 编写代码完成以下任务: ① 将地址"http://www.cbooo.cn/year?year=2019"源代码使用任意方法保存到指定文件中(文件类型不限). ② 使用文件流 ...

  7. MySQL分布式数据库架构:分库、分表、排序、分页、分组、实现教程

    MySQL分库分表总结: 单库单表 : 单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到. 单库多表 : 随着用户数量的增加, ...

  8. Maven配置环境变量

    Windows: 1:新建系统M2_HOME变量,并把安装maven路径拷贝上去 ​ 2:配置path变量,并把maven路径拷贝上去,这次的maven路径到bin ​ 3:测试maven环境是否配置 ...

  9. MySQL服务器

    ---恢复内容开始--- mysql是基于C/S端的服务器软件 mysql服务端 -server端开启 -解析指令 -对文件夹.文件.数据的增删改查 mysql客户端 -连接S段 -发送指令(sql语 ...

  10. 数据库中聚合索引(MySQL和SQL Server区别)

    一.聚集索引和非聚集索引 聚集索引:类似字典的拼音目录.表中的数据按照聚集索引的规则来存储的.就像新华字典.整本字典是按照A-Z的顺序来排列.这也是一个表只能有一个聚集索引的原因.因为这个特点,具体索 ...