标签:
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