ListView的优化

ListView作为android上最常用的控件之一,其原理与效率十分值得我们去探究,特别是当与Button、
 
ImageView一起时,许多问题便纷至沓来。今天我就说说这老生常谈的话题,也是由此做一个总结。
 
 
一,ListView的原理
 
 
在Android中有一个Recycler的构件,滑出屏幕的的Item就会被缓存在里面。但并不是缓存全部,只是
 
会根据item的类型数来缓存相应的个数。举个例子,一般情况下都没有必要去重写ListView的
 
getViewTypeCount())函数,那么type值也就为1,也就是说,Recycler中只会缓存一个item View。如
 
下图(图片来自网络):
 
 
当Item1滑出屏幕的时候,Recycler构件中就缓存了item1,再往上滑,item2滑出屏幕。这时有趣的事情
 

就发生了,Recycler构件只会缓存一个item,这时毫无争议会缓存Item2,那么item1就被复用,显示为

item8(实际上当item1完全滑出界面时就会被显示作Item8了)。

二,需要注意的地方

 1,数据与显示分离

    由于ListView的item view是复用的,这就要求我们将数据与显示分离,否则将造成显示的结果错

乱。比如,当ListView的Item中含有单选按钮时,假如只是简单地记录按钮的点击状态,那么当滑动

ListView的时候,“已点击”与“未点击”就显示混乱。再举个例子,ListView的item中含有图片,选择异步

加载。如果做法是当下载完毕后就设置ImageView的显示内容,那么也会造成混乱。

    比较明智的做法是自己单独维护一个数据结构来缓存数据,上文的点击状态就时候使用ArrayList,异

步加载的图片就适合使用HashMap。

    2,数据更新

    ListView的数据更新只能在UI主线程中进行,否则会报:“java.lang.IllegalStateException: The

content of the adapter has changed but ListView did not receive a notification. Make sure the

content of your adapter is not modified from a background thread, but only from the UI thread.”

        另外还需要注意的是,不能更改原来的数据指向的对象。比如,原来的数据List 指向的是

ArrayList1。在数据更新后,为了方便,我们直接 List = ArrayList2。这样就使List指向新的ArrayList

,也是会出错的。总而言之,唯一的做法就是在原理的ArrayList1中增加或删除数据。

    3,使用BitMap需要注意不要OOM

    使用ListView的场景里一般含有多条数据,每条数据都有BitMap的情况下很容易造成OOM。比较合

理的做法是,Bitmap要及时回收,同时,要合理地压缩Bitmap。

三,ListView的优化

    1,判断item的view是否为空

    如果view为空,就不需要去将XML布局文件转化为View,也就是达到使用recycler缓存的目的。

    2,使用ViewHolder

    在Android中,一个界面可以被组织为一棵控件树,View的绘制就是围绕这棵控件树来执行的。而

view.findViewById(int id)函数的原理是,从该View开始(包含该view)进行树的深度优先遍历,匹配最

先找到的id为参数id的view(因此android中的id不要求全局唯一,只要能保证准确获取就行)。因此

看来,findViewById这个函数是十分耗时的。因此使用一个内部类ViewHolder可以缓存住item的子控

件,使其只需要进行N次遍历(N = item中控件数 * 一屏能显示的item个数)。

    以下是例子:


   
   
01
public class MBaseAdapter extends BaseAdapter{
02
 
03
 List mList;
04
 
05
 Context mContext;
06
 
07
 ViewHolder mViewHolder;
08
 
09
 
10
 
11
 public MBaseAdapter(Context context,List list) {
12
 
13
  mContext = context;
14
 
15
  mList = list;
16
 
17
 }
18
 
19
 
20
 
21
 @Override
22
 
23
 public int getCount() {
24
 
25
  return mList.size();
26
 
27
 }
28
 
29
 
30
 
31
 @Override
32
 
33
 public Object getItem(int position) {
34
 
35
  return mList.get(position);
36
 
37
 }
38
 
39
 
40
 
41
 @Override
42
 
43
 public long getItemId(int position) {
44
 
45
  return position;
46
 
47
 }
48
 
49
 
50
 
51
 @Override
52
 
53
 public View getView(int position, View convertView, ViewGroup arg2) {
54
 
55
  if (convertView == null) {
56
 
57
   convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, null);
58
 
59
   mViewHolder = new ViewHolder();
60
 
61
   mViewHolder.tvHello = (TextView) convertView.findViewById(R.id.list_hello);
62
 
63
   convertView.setTag(mViewHolder);
64
 
65
  } else {
66
 
67
   mViewHolder = (ViewHolder)convertView.getTag();
68
 
69
  }
70
 
71
  mViewHolder.tvHello.setText(mList.get(position)+" Hello,World!");
72
 
73
 
74
 
75
  return convertView;
76
 
77
 }
78
 
79
 
80
 
81
 class ViewHolder {
82
 
83
  TextView tvHello;
84
 
85
 }
86
 
87
 
88
 
89
}

    3,在合适的状态显示合适的数据

    这里主要是监听滑动状态,当状态为滑动或者惯性滑动时不需要开加载图片,当状态为普通显示时就加载图片。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值