1. 程式人生 > >Android UI設計——ListView控制元件使用優化(五)

Android UI設計——ListView控制元件使用優化(五)

  在上一篇部落格中《Android UI設計——ListView控制元件和自定義Adapter(四) 》(連結)中我們通過一個例項來了解和練習瞭如何去自定義Adapter,本節我們將會繼續以《Android UI設計——ListView控制元件和自定義Adapter(四) 》中的例子來學習ListView在使用中是如何優化的,如果本節看著吃力的話,建議先檢視上篇哦……

convertView優化

  有時候我們在ListView中顯示的資料非常多,雖然我們手機的螢幕有限,資料可以通過滾動的方式為我們顯示。在上一節中我們在自定義的Adapter的getView方法中使用的是將資料一次性全部載入完成,以至於當我們開啟我們應用程式時速度非常慢,因為大量的資料是一次性載入完成的,降低了資料的讀取速度,增加佔用的記憶體。那麼這個時候我們就可以通過convertView來解決這個問題。

解決原理

  convertView是採用一種”快取“的方式。資料載入時首先載入在手機螢幕上出現的View,當滑動手機螢幕時,會有View被劃出螢幕,同時也會有新的View進入螢幕。此時convertView就將出屏的View儲存下來作為下一個進入螢幕的新的View使用。
  Android中有個叫做Recycler的構件,下圖是他的工作原理:
這裡寫圖片描述

  1. ListView先請求一個type1檢視(getView)然後請求其他可見的專案。convertView在getView中是空(null)的。
  2. 當item1滾出螢幕,並且一個新的專案從螢幕低端上來時,ListView再請求一個type1檢視。convertView此時不是空值了,它的值是item1。你只需設定新的資料然後返回convertView,不必重新建立一個檢視。
(此處引用於

部落格園 連結

  下面我們對我們上節的示例進行優化:

public class StudentAdapter extends BaseAdapter{

    private List<Student> mData;//定義資料。
    private LayoutInflater mInflater;//定義Inflater,載入我們自定義的佈局。

    /*
    定義構造器,在Activity建立物件Adapter的時候將資料data和Inflater傳入自定義的Adapter中進行處理。
    */
    public StudentAdapter(LayoutInflater inflater,List<Student> data){
        mInflater = inflater;
        mData = data;
    }

    @Override
public int getCount() { return mData.size(); } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertview, ViewGroup viewGroup) { /* 這是上節中的程式碼,將全部資料載入到ListView中 */ //獲得ListView中的view // View viewStudent = mInflater.inflate(R.layout.item_simpleadapter,null); //獲得學生物件 // Student student = mData.get(position); // // ImageView imagePhoto = (ImageView) viewStudent.findViewById(R.id.image_photo); // TextView name = (TextView) viewStudent.findViewById(R.id.textview_name); // TextView age = (TextView) viewStudent.findViewById(R.id.textview_age); // TextView sex = (TextView) viewStudent.findViewById(R.id.textview_sex); // TextView hobby = (TextView) viewStudent.findViewById(R.id.textview_hobby); // imagePhoto.setImageResource(student.getImag()); // name.setText(student.getName()); // age.setText(student.getAge()); // sex.setText(student.getSex()); // hobby.setText(student.getHobby()); /* convertview 優化 */ //判斷convertview 是否為空,如果為空需要對其進行佈局。 if(convertview == null){ convertview = mInflater.inflate(R.layout.item_simpleadapter,null); } //不管是否為空,都需要載入資料。 Student student = mData.get(position); ImageView imagePhoto = (ImageView) convertview.findViewById(R.id.image_photo); TextView name = (TextView) convertview.findViewById(R.id.textview_name); TextView age = (TextView) convertview.findViewById(R.id.textview_age); TextView sex = (TextView) convertview.findViewById(R.id.textview_sex); TextView hobby = (TextView) convertview.findViewById(R.id.textview_hobby); imagePhoto.setImageResource(student.getImag()); name.setText(student.getName()); age.setText(student.getAge()); sex.setText(student.getSex()); hobby.setText(student.getHobby()); return convertview; } }

ViewHolder優化

  由於fingViewById是一個耗時間的操作,在convertView優化中,雖然將View進行了快取,但還是判斷convertView是否為空後還是需要對其佈局和資料的對映,以至於消耗了時間和記憶體。此時我們可以通過ViewHolder來解決這個問題。
  在自定義的Adapter中定義一個內部類ViewHolder,通過ViewHolder將顯示在ListView中的資料通過findViewById獲取到然後在接下來不為空的convertView直接獲取ViewHolder的Tag即可。
看程式碼:

public class StudentAdapter extends BaseAdapter{

    private List<Student> mData;//定義資料。
    private LayoutInflater mInflater;//定義Inflater,載入我們自定義的佈局。

    /*
    定義構造器,在Activity建立物件Adapter的時候將資料data和Inflater傳入自定義的Adapter中進行處理。
    */
    public StudentAdapter(LayoutInflater inflater,List<Student> data){
        mInflater = inflater;
        mData = data;
    }

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

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

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

    @Override
    public View getView(int position, View convertview, ViewGroup viewGroup) {
        //建立ViewHolder的物件。
        ViewHolder viewHolder = null;
        //獲得Item位置上的資料。
        Student student = mData.get(position);
        //convertview 優化
        if(convertview == null){
            convertview = mInflater.inflate(R.layout.item_simpleadapter,null);
            viewHolder = new ViewHolder();
            viewHolder.imagePhoto = (ImageView) convertview.findViewById(R.id.image_photo);
            viewHolder.name = (TextView) convertview.findViewById(R.id.textview_name);
            viewHolder.age = (TextView) convertview.findViewById(R.id.textview_age);
            viewHolder.sex = (TextView) convertview.findViewById(R.id.textview_sex);
            viewHolder.hobby = (TextView) convertview.findViewById(R.id.textview_hobby);
        //convertview為空時,ViewHolder將顯示在ListView中的資料通過findViewById獲取到。
            convertview.setTag(viewHolder);
        }else{
            //convertview不為空時,直接獲取ViewHolder的Tag即可。
            viewHolder = (ViewHolder) convertview.getTag();
        }
        viewHolder.imagePhoto.setImageResource(student.getImag());
        viewHolder.name.setText(student.getName());
        viewHolder.age.setText(student.getAge());
        viewHolder.sex.setText(student.getSex());
        viewHolder.hobby.setText(student.getHobby());

        return convertview;
    }
    /*
    ViewHolder內部類
    */
    class ViewHolder{
        TextView name;
        TextView age;
        TextView sex;
        TextView hobby;
        ImageView imagePhoto;
    }
}

滾動變黑問題優化

  有時候會出現滾動變黑問題,解決方法是設定:cacheColorHint屬性,將值設定為透明色。在ListView控制元件佈局中設定:

android:cacheColorHint="#00000000"

設定分隔線

如圖所示的箭頭指向的分隔線是可以設定的哦:

這裡寫圖片描述

通過在ListView中新增如下語句:

android:divider="#f00000"
android:dividerHeight="2dp"