ListView和Adapter的基础知识
【问】假如Listview的item数量有10亿条的话岂不是要绘制10亿个View?
【答】肯定不可能,手机内容会没那么大...Android针对这种情况专门设计了Recycler的构件
【参考】http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html
【概要】
假如一个页面只能显示10条list内容,且每个条目的样式是一样的
那么50条内容的显示,其实只是1~10条会绘制页面 [ convertView仍然是空值 ]
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item1, null);
holder = new ViewHolder();
holder.textView = (TextView)convertView.findViewById(R.id.text);
convertView.setTag(holder);
}
当编号为1的条目向上滑动移出屏幕之后[View-1]
编号为11的条目自下进入屏幕,将会直接套用[View-1]
else {
holder = (ViewHolder)convertView.getTag();
}
看看代码
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
// 提高刷新的效率,避免卡顿
// 当子条目容器为空的时候,填充布局式样
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(
R.layout.adapter_circle_msg_item, null);
holder = new ViewHolder(convertView);
// setTag的妙用
// 绑定convertView与ViewHolder贴上Tag
convertView.setTag(holder);
} else {
// setTag的妙用
// 当convertView非空时候,直接根据Tag拿到绑定的ViewHolder【存放在缓存中的】
holder = (ViewHolder) convertView.getTag();
}
CircleMsgItemInfo info = mInfos.get(position);
holder.fillViewWithData(info);
return convertView;
}
代码解析
setTag方法是干什么的?
setTag给View对象的一个标签,标签可以是任何内容,我们这里把他设置成了一个对象
ViewHolder holder;
...
convertView.setTag(holder);
因为我们先抽象出来成为一个内部类ViewHolder,用了setTag,这个标签就是ViewHolder实例化后对象的一个属性。
我们之后对于ViewHolder实例化的对象holder的操作,都会因为java的引用机制而一直存活并改变convertView的内容,而不是每次都是去new一个,而达到重用的效果。
不使用Tag标签会怎么样呢?
第一种情况:当UI容器没用使用LayoutInflater进行View填充的时候,没必要使用。
第二种情况:当UI容器使用LayoutInflater进行View填充的时候,不使用Tag机制会造成滑动卡顿
使用Tag的必要性?
当ListView中每一个item的布局都不一样的时候,就不需要使用Tag
Tag标志是为了,提交重用的目的拟出的,没有同样的布局就没有意义了
Listview滑动UI显示异常的问题
【1】显示顺序异常的问题1-2-3-4-5-6-7-8,滑动之后可能变成2-3-4-5-6-7-8-1?
该问题在我工程中遇到的问题具有特殊性:一共只有8个item条目,且每个布局都不一样
问题处理:取代哦setTag的逻辑
【2】滑动后页面显示异常,A条目的内容可能跟B条目的内容混杂在一起
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
...
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
CircleMsgItemInfo info = mInfos.get(position);
holder.fillViewWithData(info);
return convertView;
}
public void fillViewWithData(CircleMsgItemInfo info) {
showHeaderBackground(info.getReplyHeadImg());
name.setText(info.getReplyName());
if (info.getReplyType().equals("like")) {
content.setText(R.string.friend_circle_like);
content.setTextColor(mContext.getResources().getColor(
R.color.blue_95));
TextPaint tp = content.getPaint();
tp.setFakeBoldText(true);
} else {
content.setText(EmojiUtil.formatEmoji(mContext, info.getReplyContent()));
content.setTextColor(mContext.getResources().getColor(
R.color.black));
TextPaint tp = content.getPaint();
tp.setFakeBoldText(false);
}
time.setText(FriendlyDateFormat.formatTime(info.getReplyTime()));
}
这是由于Android回收机制导致的,因为设置重用,避免单条View的重新绘制。
fillViewWithData在填充数据的时候,如果没有将item每一个内容都重写一遍的话,遗漏的部分将使用之前item中的内容
事例:
item Old data : A B C D E
item New date : a c d e {注意没有 b }
那么显示的效果 : a B c d e