通过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. C/C++读写文件的几种方法fstream fopen、fwrite()、fread()操作

    C中采用的主要是文件指针的办法,C++中对文件的操作主要运用了"文件流"(即非标准的输入输出)的思想 c读写文件fopen C 库函数 FILE *fopen(const char ...

  2. spring cloud工具的概念

    spring cloud是一个基于spring boot实现的微服务架构开发工具.它为微服务架构中涉及的配置管理.服务治理.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状态管 ...

  3. 对于Element-ui分页进行再次的封装使用

    这是我项目的分页的目录结构,话不多说,直接上代码. <template> <div class="pagination-container"> <el ...

  4. iOS UIView视图的图层控制

    1.添加视图 insertSubview:atIndex:   //放在子视图数组的具体索引位置 insertSubview:aboveSubview:   //某个子视图前面 insertSubvi ...

  5. iOS copy和mutableCopy 整理

    copy 和 mutableCopy 你真的理解吗?最近发现很多面试者基本都不能很好地回答这个问题.所以整理一下. copy和mutableCopy的概念: copy 浅拷贝,不拷贝对象本身,仅仅是拷 ...

  6. kvm虚拟机控制台登录配置

    vm虚拟机能否像xen虚拟机一样通过virsh console 一样采用字符界面进行linux虚拟机控制台呢,答案是肯定的,默认情况下该命令是不起作用的,需要修改相关文件才能实现. 本文出自:http ...

  7. SATB深入详解与问题剖析【纯理论】

    延着上一次[https://www.cnblogs.com/webor2006/p/11147893.html]的理论继续. SATB: 在G1中,使用的是SATB(Snapshot-At-The-B ...

  8. linux网络编程之posix条件变量

    今天来学习posix的最后一个相关知识----条件变量,言归正传. 下面用一个图来进一步描述条件变量的作用: 为什么呢? 这实际上可以解决生产者与消费者问题,而且对于缓冲区是无界的是一种比较理解的解决 ...

  9. 双端循环列表实现栈(python)

    # -*- coding: utf-8 -*- from collections import deque class Node(object): def __init__(self, value=N ...

  10. python装饰器,迭代器,生成器,协程

    python装饰器[1] 首先先明白以下两点 #嵌套函数 def out1(): def inner1(): print(1234) inner1()#当没有加入inner时out()不会打印输出12 ...