码迷,mamicode.com
首页 > 移动开发 > 详细

Android-对ListView的Adapter的一种简单封装

时间:2015-07-24 14:17:57      阅读:170      评论:0      收藏:0      [点我收藏+]

标签:

from:https://github.com/etao-open-source/cube-sdk/tree/master/core/src/in/srain/cube/views/list

1.先来看下使用方式:

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		ListView listview = (ListView) this.findViewById(R.id.listview);
		ListViewDataAdapter<Person> adapter = new ListViewDataAdapter<Person>(null);
		adapter.setViewHolderClass(null, PersonViewHolder.class, this);
		listview.setAdapter(adapter);
		adapter.update(getDatas());
	}
看出来跟普通的ListView的Adapter的使用唯一的区别是多了一步setViewHolderClass,其他的没有任何区别。

2.看下具体的实现

(1)ListViewDataAdapter.java

public class ListViewDataAdapter<T> extends ListViewDataAdapterBase<T> {

    protected List<T> mItemDataList;

    public ListViewDataAdapter(List<T> itemDataList) {
    	update(itemDataList);
    }
    
    @Override
    public void update(List<T> list){
    	this.mItemDataList = list;
    	this.notifyDataSetChanged();
    }
    
    public List<T> getDataList() {
        return mItemDataList;
    }

    @Override
    public int getCount() {
    	if(mItemDataList == null){
    		return 0;
    	}else{
    		return mItemDataList.size();
    	}
    }

    @Override
    public T getItem(int position) {
        if (mItemDataList.size() <= position || position < 0) {
            return null;
        }
        return mItemDataList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
}
它继承了ListViewDataAdapterBase,里面全是对数据的操作。

(2)PersonViewHolder.java

public class PersonViewHolder extends ViewHolderBase<Person>{

	private Context mContext;
	private TextView mName;
	private ImageView mImg;
	
	public PersonViewHolder(MainActivity context){
		this.mContext = context;
	}
	
	@SuppressLint("InflateParams")
	@Override
	public View createView(LayoutInflater layoutInflater) {
		View v = LayoutInflater.from(mContext).inflate(R.layout.item, null);
		mName = (TextView)v.findViewById(R.id.name);
		mImg = (ImageView)v.findViewById(R.id.image);
		return v;
	}

	@Override
	public void showData(final int position, Person itemData) {
		mName.setText(itemData.getName());
		mImg.setImageResource(itemData.getResId());
		mName.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Toast.makeText(mContext, ""+position, Toast.LENGTH_SHORT).show();
			}
		});
	}
}
可以看到,这里面全是对view的操作。通过这种方式,起到了很好的分离数据与View的效果,代码变得更整洁,看起来赏心悦目。以后,在书写Adapter的时候,只需要写ViewHolder就可以,ListViewDataAdapter大部分时候都不要做任何改动,需要改的时候只要继承这个类就可以了,大大的减少了工作量。

看些是如何来实现的:

(1)ListViewDataAdapterBase:

public abstract class ListViewDataAdapterBase<T> extends BaseAdapter {
	
    protected ViewHolderCreator<T> mViewHolderCreator;
    
    public void setViewHolderClass(final Object enclosingInstance, final Class<?> cls, final Object... args) {
        mViewHolderCreator = ViewHolderCreator.create(enclosingInstance, cls, args);
    }

    @SuppressWarnings("unchecked")
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        T itemData = getItem(position);
        ViewHolderBase<T> viewHolder = null;
        if (convertView == null || (!(convertView.getTag() instanceof ViewHolderBase<?>))) {
            viewHolder = createViewHolder(position);
            if (viewHolder != null) {
                convertView = viewHolder.createView(LayoutInflater.from(parent.getContext()));
                if (convertView != null) {
                        convertView.setTag(viewHolder);
                }
            }
        } else {
            viewHolder = (ViewHolderBase<T>) convertView.getTag();
        }
        if (viewHolder != null) {
            viewHolder.setItemData(position, convertView);
            viewHolder.showData(position, itemData);
        }
        return convertView;
    }

    @Override
    public abstract T getItem(int position);
    
    public abstract void update(List<T> list);
    
    private ViewHolderBase<T> createViewHolder(int position) {
        if (mViewHolderCreator == null) {
            throw new RuntimeException("view holder creator is null");
        }
        if (mViewHolderCreator != null) {
            return mViewHolderCreator.createViewHolder(position);
        }
        return null;
    }
}
这里面我们看到,它继承了BaseAdapter,除了重写了getView,还有两个额外的方法:setViewHolderClass()和createViewHolder();setViewHolderClass就是客户端调用的方法,它里面会去创建一个ViewHolderCreator,ViewHolderCreator就可以来创建ViewHolder。当ListView调用getView()的时候,假如convertView是空,就会利用createViewHolder()去创建ViewHolder,然后用ViewHolder去创建View。假如convertView不是空,重置一下数据和position,把convertView返回出去。

(2)ViewHolderCreator.java:

public class ViewHolderCreator<T> {

    private final Constructor<?> mConstructor;
    private Object[] mInstanceObjects;

    private ViewHolderCreator(Constructor<?> constructor, Object[] instanceObjects) {
        mConstructor = constructor;
        mInstanceObjects = instanceObjects;
    }

    public static <T> ViewHolderCreator<T> create(final Object enclosingInstance, final Class<?> cls, final Object... args) {
        if (cls == null) {
            throw new IllegalArgumentException("ViewHolderClass is null.");
        }

        // top class
        boolean isEnclosingInstanceClass = false;
        if (cls.getEnclosingClass() != null && !Modifier.isStatic(cls.getModifiers())) {
            isEnclosingInstanceClass = true;
        }

        // inner instance class should pass enclosing class, so +1
        int argsLen = isEnclosingInstanceClass ? args.length + 1 : args.length;

        final Object[] instanceObjects = new Object[argsLen];

        int copyStart = 0;
        // if it is inner instance class, first argument should be the enclosing class instance
        if (isEnclosingInstanceClass) {
            instanceObjects[0] = enclosingInstance;
            copyStart = 1;
        }

        // has copy construction parameters
        if (args.length > 0) {
            System.arraycopy(args, 0, instanceObjects, copyStart, args.length);
        }

        // fill the types
        final Class<?>[] parameterTypes = new Class[argsLen];
        for (int i = 0; i < instanceObjects.length; i++) {
            parameterTypes[i] = instanceObjects[i].getClass();
        }

        Constructor<?> constructor = null;
        try {
            constructor = cls.getDeclaredConstructor(parameterTypes);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        if (constructor == null) {
            throw new IllegalArgumentException("ViewHolderClass can not be initiated");
        }

        return new ViewHolderCreator<T>(constructor, instanceObjects);
    }

    @SuppressWarnings("unchecked")
	public ViewHolderBase<T> createViewHolder(int position) {
        Object object = null;
        try {
            boolean isAccessible = mConstructor.isAccessible();
            if (!isAccessible) {
                mConstructor.setAccessible(true);
            }
            object = mConstructor.newInstance(mInstanceObjects);
            if (!isAccessible) {
                mConstructor.setAccessible(false);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if (object == null || !(object instanceof ViewHolderBase)) {
            throw new IllegalArgumentException("ViewHolderClass can not be initiated");
        }
        return (ViewHolderBase<T>) object;
    }
}
create()方法就是利用反射得到用来创建ViewHolder的构造函数和参数,createViewHolder()反射构造出ViewHolder来。

(3)ViewHolderBase.java

public abstract class ViewHolderBase<T> {

    protected int mPosition = -1;
    protected View mCurrentView;

    public void setItemData(int position, View view) {
        mPosition = position;
        mCurrentView = view;
    }
    
    /**
     * create a view from resource Xml file, and hold the view that may be used in displaying data.
     */
    public abstract View createView(LayoutInflater layoutInflater);

    /**
     * using the held views to display data
     */
    public abstract void showData(int position, T itemData);

}
这个方式用起来非常的方便,它的核心是利用反射去创建ViewHolder,反射的坏处是对参数的类型要求非常严格,不过瑕不掩瑜,还是非常实用的。
ps:
这个也是从github上看到的一个开源实现,<a target=_blank href="https://github.com/etao-open-source/cube-sdk/tree/master/core/src/in/srain/cube/views/list">https://github.com/etao-open-source/cube-sdk/tree/master/core/src/in/srain/cube/views/list</a>


版权声明:本文为博主原创文章,未经博主允许不得转载。

Android-对ListView的Adapter的一种简单封装

标签:

原文地址:http://blog.csdn.net/goldenfish1919/article/details/47039985

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!