1. 程式人生 > >android app -- 關於listview的幾種用法(複用,不復用,半複用)解決item狀態改變的問題

android app -- 關於listview的幾種用法(複用,不復用,半複用)解決item狀態改變的問題

1.從最基本的不復用開始,也就是在Adapter 的getView方法中不使用ViewHolder。

這樣做,也就是在listView上下滑動,被隱藏的項滑出來的時候,每次都重繪一次這一項,這樣的話會耗記憶體,如果item的資料量比較大的話很有可能出現滑動卡頓的現象。明顯的卡頓是開發者最不願意看到的,所以這樣的使用方式,基本被pass掉了。

2.讓每一項進行復用,也就是增加ViewHolder 到Adapter的getView中去。具體看程式碼

package com.tdotapp.rd.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.tdotapp.rd.R; import java.util.List; /** * Created by GT on 2015/11/16. */ public class typeAdapter extends BaseAdapter { //上下文 private Context mContext; //item 中綁的資料 private
List<String> listBeans; //構造方法 public typeAdapter(Context context, List<String> listBeans) { this.mContext = context; this.listBeans = listBeans; } @Override public int getCount() { return listBeans.size(); } @Override public Object getItem(int position) { return
position; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { //ViewHolder ViewHolder viewHolder=null; //繪製每一項的時候先判斷convertView是否為空,不為空,則else裡面去複用,為空,則重新賦予item佈局 if (convertView == null) { //new出ViewHolder ,初始化佈局檔案 viewHolder = new ViewHolder(); convertView = LayoutInflater.from(mContext).inflate(R.layout.type_spinner_item, null); viewHolder.tvfabuwz = (TextView) convertView.findViewById(R.id.tvfabuwz); //呼叫convertView的setTag方法,將viewHolder放入進去,用於下次複用 convertView.setTag(viewHolder); } else { //複用已經存在的item的項 viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.tvfabuwz.setText(listBeans.get(position)); return convertView; } class ViewHolder { TextView tvfabuwz; } }
程式碼上增加了詳細的註釋,複用絕對是listView最優的優化方案,不用每次都繪製新的item項,建立一次,之後就拿來複用介面,這樣一來,再多的項也不用卡耗記憶體了。原理相當於在上滑和下滑的時候,介面還是原來的,只是把資料換了一下。

複用有複用的好處,當然也有壞處。使用複用的時候,如果每一項裡面只是展示資料,複用絕對好使,但是如果listView中的每一項都能操作(比如有個editText,輸入內容,上下滑動之後,看輸入框裡面的內容是不是要被改變,或者在下面複用的時候出現了這個輸入框裡面的內容。比如,一個單選框,這一項選中之後,上下滑動之後,看這個選中狀態是不是亂跑了,之前的選中狀態是不是消失了。。。。。等等等,凡是與item項狀態有關的,複用的時候肯定就出問題了)

怎麼解決呢,這個時候你想到的肯定是不復用吧,不復用就不會出現狀態改變的情況了,但是你要想清楚,不復用的話,或許滑動一會,你的這個listView就會因為不停重繪item介面而記憶體消耗過大,出現滑不動的情況。

下面就來說下如何避免這樣的情況出現,即保證滑動之後item項修改的狀態還在,又保證不會過多的重繪item使記憶體消耗多大。

本方法出自 xiaanming大牛的部落格(稍做改動)

public class NewsAdapter extends BaseAdapter {

    // 定義Context
private Context mContext;
List<NewsListBean> list = new ArrayList<>();
//定義hashMap 用來存放之前建立的每一項item
HashMap<Integer, View> lmap = new HashMap<Integer, View>();
    private ImageLoader imageLoader = ImageLoader.getInstance();
    public NewsAdapter(Context context, List<NewsListBean> listViewList) {
        this.mContext = context;
        this.list = listViewList;
}

    @Override
public int getCount() {
        return list.size();
}

    @Override
public Object getItem(int position) {
        return position;
}

    @Override
public long getItemId(int position) {
        return 0;
}

    @Override
public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder ViewHolder;
//建立每一個滑動出來的item項,將創建出來的項,放入陣列中,為下次複用使用
if (lmap.get(position) == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.news_item, null);
ViewHolder = new ViewHolder(convertView);
convertView.setTag(ViewHolder);
lmap.put(position,convertView);
} else {
            convertView = lmap.get(position);
ViewHolder = (ViewHolder) convertView.getTag();
}
    ViewHolder.tv_newstime.setText(list.get(position).getDate());
ViewHolder.tvnewsneirong.setText(list.get(position).getContent());
ViewHolder.tvnewstitle.setText(list.get(position).getTitle());
imageLoader.displayImage(list.get(position).getImg(), ViewHolder.imgnewspic, Tools.setBeforImageoption());
    return convertView;
}

//新增viewHolder
class ViewHolder {
    TextView tvnewstitle,newstype,tvnewsneirong,tv_newstime;
ImageView imgnewspic;
    public ViewHolder(View convertView) {
        tvnewstitle = (TextView) convertView.findViewById(R.id.tvnewtitle);
imgnewspic = (ImageView) convertView.findViewById(R.id.imgnewspic);
newstype= (TextView) convertView.findViewById(R.id.newstype);
tvnewsneirong= (TextView) convertView.findViewById(R.id.tvnewsneirong);
tv_newstime= (TextView) convertView.findViewById(R.id.tv_newstime);
}
}

原理就是,有新的介面了,重繪,已經存在的介面直接拿出來。這樣一來,每一次的新的item項會被重新繪製介面,並將重繪的介面放入集合中做儲存,可以有效的防止item項狀態因服用被改變的問題出現。

但是這樣的話,複用將大打折扣。記憶體消耗也會有所提升。

看夏大的部落格回覆中,有大神提到可以將狀態也同時放入tag中做儲存,同樣在實現複用的時候複用狀態。

如有不明確的地方,可以回覆,榮幸與各位開發者公共探討。
原創文章,轉載請註明出處: http://blog.csdn.net/qq_33078541?viewmode=contents