Android開發之ListView最佳化方案

來源:互聯網
上載者:User

我們使用ViewHolder時,把每一個item的子View控制項對象都放在ViewHolder中,當第一次建立convertView對象時,便把這些item的子View控制項對象findViewById執行個體化出來並儲存到ViewHolder的對象中。然後用convertView的setTag將viewHolder對象設定到Tag中, 當以後載入ListView的item時便可以直接從Tag中取出複用ViewHolder對象中的,不需要再findViewById找item的子控制項對象了。這樣便大大提高了效能。

但是,某些情況下,這種最佳化技術便出現了一種問題,舉個例子,當我們由於項目需要,需要在ListView中用到CheckBox時,那麼,就會出現這樣的情況:

假設一個ListView有10個Item,當我選擇第一個Item的CheckBox之後,往下滑動到原先不可見的位置時就會發現,還有其他的CheckBox也被選中了,這樣就造成了很不好的使用者體驗。

先上出現了這種問題的代碼:

布局檔案:

activity_listview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
<ListView
    android:id="@+id/listview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"></ListView>
</LinearLayout>
item_list.xml   一個CheckBox和一個TextView,設為100dp高的原因是,必須有未顯示的Item,ListView才會去複用View,如果一個螢幕顯示了全部的Item,那麼就不回複用了。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="100dp">
    <CheckBox
        android:layout_centerVertical="true"
        android:layout_marginLeft="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/textView"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>
</LinearLayout>
MyAdapter.java

package cn.zmit.myapplication;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;


/**
 * Created by Administrator on 2016/3/23.
 */
public class MyAdapter extends BaseAdapter {
    private List<String> list;
    private Context context;

    public MyAdapter(List<String> lists, Context contexts) {

        list = lists;
        context = contexts;
    }

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

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

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


    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = View.inflate(context, R.layout.item_list, null);
            holder.textView = (TextView) convertView.findViewById(R.id.textView);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.textView.setText(list.get(position));

        return convertView;
    }

    private class ViewHolder {
        TextView textView;
    }
}
ListVeiwDemo.java

package cn.zmit.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2016/3/18.
 */
public class ListViewDemo extends Activity {
    private ListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_listview);
        listView= (ListView) findViewById(R.id.listview);
        List<String> list=new ArrayList<>();
        for(int i=0;i<10;i++){
            list.add(i+"");
        }
        MyAdapter adapter=new MyAdapter(list,this);
        listView.setAdapter(adapter);
    }

}
 

非常正常的一個ListView實現過程,貼代碼的原因是擔心有初學者不懂我在說什麼。大家可以把代碼拷貝一下或者自己編寫看一下效果。

 

接下來說一下怎麼解決!!!!
首先,定義一個Map,

Map<Integer,View>map=new HashMap<>();
當convertView為null時,在convertView和子控制項載入完成後,將convertView加入map:

map.put(position,convertView);
我們想一想,這時候,在前面判斷的時候,還應該是

if (convertView == null)
這樣嗎?當然不是,換成這樣:

if (map.get(position)==null)
也就是說,只要你這個Item沒被載入過,就給我重新載入!

然後在下面的else裡這樣寫:

else {
    convertView=map.get(position);
    holder = (ViewHolder) convertView.getTag();
}
假設map裡有這個View,就拿出來用。

全部解決完問題的Adapter的getView部分代碼為:
Map<Integer,View>map=new HashMap<>();
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (map.get(position)==null) {
        holder = new ViewHolder();
        convertView = View.inflate(context, R.layout.item_list, null);
        holder.textView = (TextView) convertView.findViewById(R.id.textView);
        map.put(position,convertView);
        convertView.setTag(holder);
    } else {
        convertView=map.get(position);
        holder = (ViewHolder) convertView.getTag();
    }
    holder.textView.setText(list.get(position));

    return convertView;
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.