ListView中含有Button时setOnclickListener应写在Adapter的什么地方

做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);。好了,今天就说到这里,测试项目的下载地址如下。

项目下载地址


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值