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