做Android开发,ListView是最常见不过了,因此对于ListView的自定义Adapter写法,应该也非常的熟悉,高效的Adapter编码,会使得携带大量ListView的数据展现显得非常容易。关于Adapter的写法,网上也有很多的例子,在此不再唠叨。为了提高ListView重绘时对已有对象的复用大抵是这样的:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = View.inflate(mContext, R.layout.listview_item, null);
holder = new ViewHolder();
holder.no = (TextView) convertView.findViewById(R.id.no);
holder.click = (TextView) convertView.findViewById(R.id.click);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
String value = list.get(position);
holder.no.setText(value);
OnClick listener = new OnClick(position);
holder.click.setOnClickListener(listener);
Log.d(TAG,
"position is " + position + " listener is "
+ listener.toString());
return convertView;
}
在这里我们讨论的是在ListView当中含有需要处理OnClick事件的写法,之前也写过一篇
关于ListView当中含有Spinner的处理情况,这篇文章讲了如何处理Spinner的Onlick事件和对其状态的保持。虽然Onclick事件处理的比较高效,但是在方法上还有待提高。以下文章将列举出网上关于ListView中含有Onclick事件需要处理的普遍写法和本文的重点推荐高效写法。
普遍写法:
package com.yang.listviewclick.adapter;
import java.util.List;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.yang.listviewclick.R;
public class IneffectiveListViewAdapter extends BaseAdapter {
private Context mContext;
private List<String> list = null;
private static final String TAG = "ListViewAdapter";
public IneffectiveListViewAdapter(Context mContext, List<String> list) {
this.mContext = mContext;
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
class ViewHolder {
TextView no;
TextView click;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = View.inflate(mContext, R.layout.listview_item, null);
holder = new ViewHolder();
holder.no = (TextView) convertView.findViewById(R.id.no);
holder.click = (TextView) convertView.findViewById(R.id.click);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
String value = list.get(position);
holder.no.setText(value);
//问题出在这里,对于每次重绘,都新建了一个listener对象进行处理
OnClick listener = new OnClick(position);
holder.click.setOnClickListener(listener);
Log.d(TAG,
"position is " + position + " listener is "
+ listener.toString());
return convertView;
}
class OnClick implements OnClickListener {
private int position;
public OnClick(int position){
this.position = position;
}
@Override
public void onClick(View v) {
Log.d(TAG, list.get(position));
}
}
}
这种写法能够实现基本功能,即在点击某个组件时,它能够准确的定位到所点击的那个条目,并作出相应的处理。那么这是一种高效的写法吗?我们打印以下它的listener.
大家知道
position is 19 listener is com.yang.listviewclick.adapter.IneffectiveListViewAdapter$OnClick@4057f250
@后面的值是这个对象的HashCode,对于不同的对象来说,其
HashCode是不同的,而这里打印出来的所有HashCode都不相同,说明每次拖动ListView,其会对每个条目重新申请一个对象,而且这些对象不是复用的,是全新的对象。你可以想象以下,如果有一千个条目,这拖动一次就是一千个对象,而且你再回到顶部又是一千个对象,效率可见一斑。
推荐写法:
package com.yang.listviewclick.adapter;
import java.util.List;
import com.yang.listviewclick.R;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class EffectiveListViewAdapter extends BaseAdapter {
private Context mContext;
private List<String> list = null;
private static final String TAG = "ListViewAdapter";
public EffectiveListViewAdapter(Context mContext, List<String> list) {
this.mContext = mContext;
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
class ViewHolder {
TextView no;
TextView click;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
OnClick listener = null;
if (convertView == null) {
convertView = View.inflate(mContext, R.layout.listview_item, null);
holder = new ViewHolder();
holder.no = (TextView) convertView.findViewById(R.id.no);
holder.click = (TextView) convertView.findViewById(R.id.click);
listener = new OnClick();//在这里新建监听对象
holder.click.setOnClickListener(listener);
convertView.setTag(holder);
convertView.setTag(holder.click.getId(), listener);//对监听对象保存
} else {
holder = (ViewHolder) convertView.getTag();
listener = (OnClick) convertView.getTag(holder.click.getId());//重新获得监听对象
}
String value = list.get(position);//设置监听对象的值
holder.no.setText(value);
listener.setPosition(position);
Log.d(TAG,
"position is " + position + " listener is "
+ listener.toString());
return convertView;
}
class OnClick implements OnClickListener {
int position;
public void setPosition(int position) {
this.position = position;
}
@Override
public void onClick(View v) {
Log.d(TAG, list.get(position));
}
}
}
打印以下Listener
大家可以看到,这里监听对象实现了复用。每次滑动都是第一次创建的监听对象的复用。
实现这种机制的关键就是,使用convertView.setTag(holder.click.getId(), listener);对已有的对象进行保存,同时在使用时,使用listener = (OnClick) convertView.getTag(holder.click.getId())再获得这些对象。同时对这些复用的对象赋予不同的值listener.setPosition(position);。好了,今天就说到这里,测试项目的下载地址如下。
项目下载地址