android listview常用方法,Android中ListView常见优化方案

我们设置或者优化ListView的性能很多时候都是在getView中完成的,反过来说就是很多性能问题都是由于没有正确使用getView造成的。

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

那么问题就来了。

在一次显示ListView的界面时,getView会被执行几次?

在绘制ListView前往往要计算它的高度,所以一个ListView界面上可以看到6个ItemView,但是getView的执行次数却有可能是12次,多出的次数用来计算高度(这个可以通过设置ListView的height为0来避免)。所以要避免在getView中进行逻辑运算,两次计算同一逻辑完全是浪费。

每次getView执行时间有多久?

1秒之内屏幕大概可以完成30帧的绘制,人才能看到它比较流畅,每帧可使用的时间:1000ms/30 = 33.33 ms,每个ListView一般要显示6个ListItem,加上1个重用convertView:33.33ms/7 = 4.76ms,即是说,每个getView要在4.76ms内完成工作才会较流畅,但是事实上,每个getView间的调用也会有一定的间隔(有可能是由于handler在处理别的消息),UI的handler处理不好的话,这个间隔也可难会很大(0ms-200ms)。结论就是,留给getView使用的时间应该在4ms之内,如果不能控制在这之内的话,ListView的滑动就会有卡顿的现象。

(转载:Android面试一天一题(11 Day) —— goeasyway)

有哪些常见的优化方案?

1. 使用ConvertView

也是最普通的优化,就在MyAdapter类中的getView方法中,我们注意到,上面的写法每次需要一个View对象时,都是去重新inflate一个View出来返回去,没有实现View对象的复用,而实际上对于ListView而言,只需要保留能够显示的最大个数的view即可,其他新的view可以通过复用的方式使用消失的条目的view,而getView方法里也提供了一个参数:convertView,这个就代表着可以复用的view对象,当然这个对象也可能为空,当它为空的时候,表示该条目view第一次创建,所以我们需要inflate一个view出来,所以在这里,我们使用下面这种方式来重写getView方法:

@Override

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

View view;

// 判断convertView的状态,来达到复用效果

if (null == convertView) {

//如果convertView为空,则表示第一次显示该条目,需要创建一个view

view = View.inflate(MainActivity.this, R.layout.listview_item,null);

} else {

//否则表示可以复用convertView

view = convertView;

}

// listview_item里只有一个textview

TextView tv_item = (TextView) view.findViewById(R.id.tv_item);

tv_item.setText(list.get(position));

return view;

}

2. 使用View Holder模式

经过上面的优化之后,我们不需要每一个view都重新生成了。下面我们来解决下一个每一次都需要做的工作,那就是view中组件的查找:

TextView tv_item = (TextView) view.findViewById(R.id.tv_item);

实际上,findViewById是到xml文件中去查找对应的id,可以想象如果组件多的话也是挺费事的,如果我们可以让view内的组件也随着view的复用而复用,就能对ListView进行很好的优化

private static class ViewHolder {

private TextView tvHolder;

}

@Override

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

View view;

ViewHolder holder;

// 判断convertView的状态,来达到复用效果

if (null == convertView) {

// 如果convertView为空,则表示第一次显示该条目,需要创建一个view

view = View.inflate(MainActivity.this, R.layout.listview_item, null);

//新建一个viewholder对象

holder = new ViewHolder();

//将findviewbyID的结果赋值给holder对应的成员变量

holder.tvHolder = (TextView) view.findViewById(R.id.tv_item);

// 将holder与view进行绑定

view.setTag(holder);

} else {

// 否则表示可以复用convertView

view = convertView;

holder = (ViewHolder) view.getTag();

}

// 直接操作holder中的成员变量即可,不需要每次都findViewById

holder.tvHolder.setText(list.get(position));

return view;

}

ps:

这里的ViewHolder类需要不需要定义成static,根据实际情况而定,如果item不是很多的话,可以使用,这样在初始化的时候,只加载一次,可以稍微得到一些优化。

不过,如果item过多的话,建议不要使用。因为static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(比如Context的情况最多),这时就要尽量避免使用了。

3. 分批加载与分页加载相结合

我们需要进行分批加载,比如说1000条新闻的List集合,我们一次加载20条,等到用户翻页到底部的时候,我们再添加下面的20条到List中,再使用Adapter刷新ListView,这样用户一次只需要等待20条数据的传输时间,不需要一次等待好几分钟把数据都加载完再在ListView上显示。其次这样也可以缓解很多条新闻一次加载进行产生OOM应用崩溃的情况。

实际上,分批加载也不能完全解决问题,因为虽然我们在分批中一次只增加20条数据到List集合中,然后再刷新到ListView中去,假如有10万条数据,如果我们顺利读到最后这个List集合中还是会累积海量条数的数据,还是可能会造成OOM的情况,这时候我们就需要用到分页,比如说我们将这10万条数据分为1000页,每一页100条数据,每一页加载时都覆盖掉上一页中List集合中的内容,然后每一页内再使用分批加载,这样用户的体验就会相对好一些。

除此之前还有一些优化建议:

使用异步线程加载图片(一般都是直接使用图片库加载,如Glide, Picasso);

在adapter的getView方法中尽可能的减少逻辑判断,特别是耗时的判断;

避免GC(可以从LOGCAT查看有无GC的LOG);

在快速滑动时不要加载图片;

将ListView的scrollingCache和animateCache这两个属性设置为false(默认是true);

尽可能减少List Item的Layout层次(如可以使用RelativeLayout替换LinearLayout,或使用自定的View代替组合嵌套使用的Layout);

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值