通过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. https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce/repodata/repomd.xml:HTTPS Error 404 - Not Found

    1.按照菜鸟教程,安装docker,竟然报如题错误 2.然后发现,自己再添加软件源信息的时候,自作聪明的把centos换成了自己的主机名 3.那么需要重新来,先删除 cd  /etc/yum.repo ...

  2. FICO-清帐函数

    转载:https://www.cnblogs.com/caizjian/p/8067071.html https://blog.csdn.net/sapliumeng/article/details/ ...

  3. git pull 的时候 把本地的修改 覆盖远程端

    首先,git pull 可以分成两步,git fetch 和git merge 使用git branch -a可以看出来    git merge 相当于当前分支  和 origin/master分支 ...

  4. git 打tag标着版本

    1.git tag v1.0 2.git push origin v1.0

  5. Powershell-常用脚本

    function Test-Port { Param([string]$ComputerName,$port = 5985,$timeout = 1000) try { $tcpclient = Ne ...

  6. Git与其他VCS的差异

    推荐:Git essentials  一共4集视频 对待数据 在对待不同版本数据问题上,分为两派:差异增量.直接快照 增量差异 Git 和其它版本控制系统(包括 Subversion 和近似工具)的主 ...

  7. SpringBoot下,@WebFilter配置获取日志

    CREATE TABLE [dbo].[SWEBSERVICELOG]( [WLG_ID] [varchar](100) NOT NULL, [WLG_SESSIONID] [varchar](100 ...

  8. Linux网络编程综合运用之MiniFtp实现(五)

    转眼兴奋的五一小长假就要到来了,在放假前夕还是需要保持一颗淡定的心,上次中已经对miniFTP有基础框架进行了搭建,这次继续进行往上加代码,这次主要还是将经历投射到handle_child()服务进程 ...

  9. MySQL进阶11--DDL数据库定义语言--库创建/修改/删除--表的创建/修改/删除/复制

    /*进阶 11 DDL 数据库定义语言 库和表的管理 一:库的管理:创建/修改/删除 二:表的管理:创建/修改/删除 创建: CREATE DATABASE [IF NOT EXISTS] 库名; 修 ...

  10. cookie和session基础知识学习

    一.session的简单使用 session是服务器端技术,服务器在运行时可以为每一个用户的浏览器创建一个独享的session对象.session的使用步骤: 获取session对象使用session ...