android gridview 动态加载数据,GridView异步加载中一次加载完所有数据问题的解决以及其原因分析...

今天在开发一个相册应用的时候遇到一个很奇怪的问题,用于显示照片的GridView在显示的时候,初次加载,getView就被调用了1000次,而我的所有图片也只有1000张,也就是说在还没有滚动的情况下GridView就已经把所有的数据显示完了(当然超出屏幕的是看不见的),但是GridView本身是只显示视野范围内的数据项的啊。如果这样GridView的子view复用还有什么意义,GridView一直都是按需加载的啊。

下面是getView中打印出来的position值

6c7ce563e0c7f61377a8dcb9de7685e6.png

显示安卓系统中图片是肯定需要异步加载的,如果一次就异步的方式去加载1000张照片,所消耗的系统资源可想而知,实际情况是我的应用直接就黑屏了。而即便没有开启异步加载如果第一次getView就调用了1000次,那么说明一次就生成了1000个子View,这样虽然应用不会死,也会出现上图中的渲染警告:Skipped 77 frames!  The application may be doing too much work on its main thread.

出现这个问题让我很无奈,因为我根本就不知道我到底哪里错了,我都是按照正常方式来使用GridView的。

经过无数次debug,终于找出了问题的所在。

为了复线出这种情况,先讲讲我是如何使用的。之所以把这两部分代码提出来,是因为用替换法我发现问题就出在这里。

用于显示照片的GridView的adapter中getView 是这样实现的:@Override

public View getView(final int position, View convertView, ViewGroup parent) {

if (DEBUG)

Log.i(TAG, "position = " + position);

ViewHolder holder = null;

if (convertView == null) {

convertView = mLayoutInflater.inflate(R.layout.item_image,

null);

holder = new ViewHolder();

holder.imageView = (ImageView) convertView .findViewById(R.id.imageView);

convertView.setTag(holder);

}

holder = (ViewHolder) convertView.getTag();

mLoader.DisplayImage(mImageList.get(position), holder.imageView);

return convertView;

}

其中mLoader.DisplayImage(mImageList.get(position), holder.imageView);是开启一个加载图片的线程,也就是异步加载。

R.layout.item_image代码如下:<?xml version="1.0" encoding="utf-8"?>

android:layout_width="fill_parent"

android:layout_height="wrap_content"

>

android:id="@+id/imageView"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:scaleType="fitXY"

android:src="@null" />

如上使用,则会出现刚刚提到的怪异情况。

但是我发现在ImageView中,android:layout_height设置一个高度就不会出现这样的问题。或者是给ImageView设置一个padding也不会出现这样的问题,这些高度值我试了不同的数值,发现值越小,getView调用的次数越多,当为1px的时候差不多就接近1000次了,其实这个很好理解,因为值越小 每个item的高度越小,可见范围内就能显示越多的item。但是这个数值接近1000则给我我很大的触动。我一下意识到这个跟ImageView的layout_height为wrap_content有关。

因为ImageView的图片资源是异步加载,所以在getView返回returnconvertView的时候ImageView其实是没有任何内容的,而wrap_content也就意味着其实际高度为0,因此不管你的ImageView在异步数据完成之后有多大,GridView都认为自己的高度足以显示完所有的item(因为在返回convertView的时候高度为0)。

找到了问题之后我们对症下药,完美解决。

但是还是有必要总结一下出现这种情况的时机,因为一般情况很少见,我看网上也很少有人提到这个问题,唯一看到有人对此提问还是在stackoverflow上,而且没有人回答正确 http://stackoverflow.com/questions/11152992/forbid-gridview-to-load-all-views-at-once。

1.item的xml中的控件不管有多少层,必须是可能有一个高度为0的情况出现,比如ImageView或者是LinearLayout高度为wrap_content,如果是有类似于TextView的控件,则绝不会出出现这种bug,因为TextView是有一个默认最小高度的。

2.通常情况下发生在异步加载的时候,因为即便ImageView或者是LinearLayout高度为wrap_content,如果不是异步加载,他们的内容都会立马赋值,所以就会产生一个实际高度。

3.最普遍的是内容只是单个ImageView的情况,因为wrap_content的ImageView在没有设置图片资源之前,高度是为0的。而且真正需要异步加载的往往也只有ImageView。

最后给点建议:

虽然上面说item中有TextView绝不会出现无尽的加载完所有数据的异常情况,但是我们还是希望TextView(或者其他)能够在返回convertView之前确保高度是和实际内容一致的,不然即便是没有加载很多,也是多余预期的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值