ListView和Adapter的基礎知識html
【問】假如Listview的item數量有10億條的話豈不是要繪製10億個View?java
【答】確定不可能,手機內容會沒那麼大...Android針對這種狀況專門設計了Recycler的構件緩存
【參考】http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.htmlide
【概要】佈局
假如一個頁面只能顯示10條list內容,且每一個條目的樣式是同樣的spa
那麼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]code
編號爲11的條目自下進入屏幕,將會直接套用[View-1]orm
else { holder = (ViewHolder)convertView.getTag(); }
看看代碼
htm
@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