Android 快速开发系列 打造万能的ListView GridView 适配器

来源:互联网 发布:郑亚旗 知乎 编辑:程序博客网 时间:2024/06/04 18:42

转载出处:http://blog.csdn.net/lmj623565791/article/details/38902805 ,本文出自【张鸿洋的博客】

1、概述

相信做Android开发的写得最多的就是ListView,GridView的适配器吧,记得以前开发一同事开发项目,一个项目下来基本就一直在写ListView的Adapter都快吐了~~~对于Adapter一般都继承BaseAdapter复写几个方法,getView里面使用ViewHolder模式,其实大部分的代码基本都是类似的。

本篇博客为快速开发系列的第一篇,将一步一步带您封装出一个通用的Adapter。

2、常见的例子

首先看一个最常见的案例,大家一目十行的扫一眼

1、布局文件

主布局文件:

[html] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. <RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”  
  2.     xmlns:tools=“http://schemas.android.com/tools”  
  3.     android:layout_width=“match_parent”  
  4.     android:layout_height=“match_parent” >  
  5.   
  6.     <ListView  
  7.         android:id=“@+id/id_lv_main”  
  8.         android:layout_width=“fill_parent”  
  9.         android:layout_height=“fill_parent” />  
  10.   
  11. </RelativeLayout>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <ListView        android:id="@+id/id_lv_main"        android:layout_width="fill_parent"        android:layout_height="fill_parent" /></RelativeLayout>

Item的布局文件:

[html] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. <?xml version=“1.0” encoding=“utf-8”?>  
  2. <TextView xmlns:android=“http://schemas.android.com/apk/res/android”  
  3.     android:id=“@+id/id_tv_title”  
  4.     android:layout_width=“match_parent”  
  5.     android:layout_height=“50dp”  
  6.     android:background=“#aa111111”  
  7.     android:gravity=“center_vertical”  
  8.     android:paddingLeft=“15dp”  
  9.     android:textColor=“#ffffff”  
  10.     android:text=“hello”  
  11.     android:textSize=“20sp”  
  12.     android:textStyle=“bold” >  
  13.   
  14. </TextView>  
<?xml version="1.0" encoding="utf-8"?><TextView xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/id_tv_title"    android:layout_width="match_parent"    android:layout_height="50dp"    android:background="#aa111111"    android:gravity="center_vertical"    android:paddingLeft="15dp"    android:textColor="#ffffff"    android:text="hello"    android:textSize="20sp"    android:textStyle="bold" ></TextView>

2、Adapter

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. package com.example.zhy_baseadapterhelper;  
  2.   
  3. import java.util.List;  
  4.   
  5. import android.content.Context;  
  6. import android.view.LayoutInflater;  
  7. import android.view.View;  
  8. import android.view.ViewGroup;  
  9. import android.widget.BaseAdapter;  
  10. import android.widget.TextView;  
  11.   
  12. public class MyAdapter extends BaseAdapter  
  13. {  
  14.     private LayoutInflater mInflater;  
  15.     private Context mContext;  
  16.     private List<String> mDatas;  
  17.   
  18.     public MyAdapter(Context context, List<String> mDatas)  
  19.     {  
  20.         mInflater = LayoutInflater.from(context);  
  21.         this.mContext = context;  
  22.         this.mDatas = mDatas;  
  23.     }  
  24.   
  25.     @Override  
  26.     public int getCount()  
  27.     {  
  28.         return mDatas.size();  
  29.     }  
  30.   
  31.     @Override  
  32.     public Object getItem(int position)  
  33.     {  
  34.         return mDatas.get(position);  
  35.     }  
  36.   
  37.     @Override  
  38.     public long getItemId(int position)  
  39.     {  
  40.         return position;  
  41.     }  
  42.   
  43.     @Override  
  44.     public View getView(int position, View convertView, ViewGroup parent)  
  45.     {  
  46.         ViewHolder viewHolder = null;  
  47.         if (convertView == null)  
  48.         {  
  49.             convertView = mInflater.inflate(R.layout.item_single_str, parent,  
  50.                     false);  
  51.             viewHolder = new ViewHolder();  
  52.             viewHolder.mTextView = (TextView) convertView  
  53.                     .findViewById(R.id.id_tv_title);  
  54.             convertView.setTag(viewHolder);  
  55.         } else  
  56.         {  
  57.             viewHolder = (ViewHolder) convertView.getTag();  
  58.         }  
  59.         viewHolder.mTextView.setText(mDatas.get(position));  
  60.         return convertView;  
  61.     }  
  62.   
  63.     private final class ViewHolder  
  64.     {  
  65.         TextView mTextView;  
  66.     }  
  67.   
  68. }  
package com.example.zhy_baseadapterhelper;import java.util.List;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;public class MyAdapter extends BaseAdapter{    private LayoutInflater mInflater;    private Context mContext;    private List<String> mDatas;    public MyAdapter(Context context, List<String> mDatas)    {        mInflater = LayoutInflater.from(context);        this.mContext = context;        this.mDatas = mDatas;    }    @Override    public int getCount()    {        return mDatas.size();    }    @Override    public Object getItem(int position)    {        return mDatas.get(position);    }    @Override    public long getItemId(int position)    {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent)    {        ViewHolder viewHolder = null;        if (convertView == null)        {            convertView = mInflater.inflate(R.layout.item_single_str, parent,                    false);            viewHolder = new ViewHolder();            viewHolder.mTextView = (TextView) convertView                    .findViewById(R.id.id_tv_title);            convertView.setTag(viewHolder);        } else        {            viewHolder = (ViewHolder) convertView.getTag();        }        viewHolder.mTextView.setText(mDatas.get(position));        return convertView;    }    private final class ViewHolder    {        TextView mTextView;    }}

3、Activity

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. package com.example.zhy_baseadapterhelper;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Arrays;  
  5. import java.util.List;  
  6.   
  7. import android.app.Activity;  
  8. import android.os.Bundle;  
  9. import android.widget.ListView;  
  10.   
  11. public class MainActivity extends Activity  
  12. {  
  13.   
  14.     private ListView mListView;  
  15.     private List<String> mDatas = new ArrayList<String>(Arrays.asList(“Hello”,  
  16.             ”World”“Welcome”));  
  17.     private MyAdapter mAdapter;  
  18.   
  19.     @Override  
  20.     protected void onCreate(Bundle savedInstanceState)  
  21.     {  
  22.         super.onCreate(savedInstanceState);  
  23.         setContentView(R.layout.activity_main);  
  24.         mListView = (ListView) findViewById(R.id.id_lv_main);  
  25.         mListView.setAdapter(mAdapter = new MyAdapter(this, mDatas));  
  26.   
  27.     }  
  28.   
  29. }  
package com.example.zhy_baseadapterhelper;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.widget.ListView;public class MainActivity extends Activity{    private ListView mListView;    private List<String> mDatas = new ArrayList<String>(Arrays.asList("Hello",            "World", "Welcome"));    private MyAdapter mAdapter;    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mListView = (ListView) findViewById(R.id.id_lv_main);        mListView.setAdapter(mAdapter = new MyAdapter(this, mDatas));    }}

上面这个例子大家应该都写了无数遍了,MyAdapter集成BaseAdapter,然后getView里面使用ViewHolder模式;一般情况下,我们的写法是这样的:对于不同布局的ListView,我们会有一个对应的Adapter,在Adapter中又会有一个ViewHolder类来提高效率。

这样出现ListView就会出现与之对于的Adapter类、ViewHolder类;那么有没有办法减少我们的编码呢?

下面首先拿ViewHolder开刀~

3、通用的ViewHolder

首先分析下ViewHolder的作用,通过convertView.setTag与convertView进行绑定,然后当convertView复用时,直接从与之对于的ViewHolder(getTag)中拿到convertView布局中的控件,省去了findViewById的时间~

也就是说,实际上们每个convertView会绑定一个ViewHolder对象,这个viewHolder主要用于帮convertView存储布局中的控件。

那么我们只要写出一个通用的ViewHolder,然后对于任意的convertView,提供一个对象让其setTag即可;

既然是通用,那么我们这个ViewHolder就不可能含有各种控件的成员变量了,因为每个Item的布局是不同的,最好的方式是什么呢?

提供一个容器,专门存每个Item布局中的所有控件,而且还要能够查找出来;既然需要查找,那么ListView肯定是不行了,需要一个键值对进行保存,键为控件的Id,值为控件的引用,相信大家立刻就能想到Map;但是我们不用Map,因为有更好的替代类,就是我们android提供的SparseArray这个类,和Map类似,但是比Map效率,不过键只能为Integer.

下面看我们的ViewHolder类:

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. package com.example.zhy_baseadapterhelper;  
  2.   
  3. import android.content.Context;  
  4. import android.util.Log;  
  5. import android.util.SparseArray;  
  6. import android.view.LayoutInflater;  
  7. import android.view.View;  
  8. import android.view.ViewGroup;  
  9.   
  10. public class ViewHolder  
  11. {  
  12.     private final SparseArray<View> mViews;  
  13.     private View mConvertView;  
  14.   
  15.     private ViewHolder(Context context, ViewGroup parent, int layoutId,  
  16.             int position)  
  17.     {  
  18.         this.mViews = new SparseArray<View>();  
  19.         mConvertView = LayoutInflater.from(context).inflate(layoutId, parent,  
  20.                 false);  
  21.         //setTag  
  22.         mConvertView.setTag(this);  
  23.           
  24.           
  25.     }  
  26.   
  27.     /** 
  28.      * 拿到一个ViewHolder对象 
  29.      * @param context 
  30.      * @param convertView 
  31.      * @param parent 
  32.      * @param layoutId 
  33.      * @param position 
  34.      * @return 
  35.      */  
  36.     public static ViewHolder get(Context context, View convertView,  
  37.             ViewGroup parent, int layoutId, int position)  
  38.     {  
  39.       
  40.         if (convertView == null)  
  41.         {  
  42.             return new ViewHolder(context, parent, layoutId, position);  
  43.         }  
  44.         return (ViewHolder) convertView.getTag();  
  45.     }  
  46.   
  47.   
  48.     /** 
  49.      * 通过控件的Id获取对于的控件,如果没有则加入views 
  50.      * @param viewId 
  51.      * @return 
  52.      */  
  53.     public <T extends View> T getView(int viewId)  
  54.     {  
  55.           
  56.         View view = mViews.get(viewId);  
  57.         if (view == null)  
  58.         {  
  59.             view = mConvertView.findViewById(viewId);  
  60.             mViews.put(viewId, view);  
  61.         }  
  62.         return (T) view;  
  63.     }  
  64.   
  65.     public View getConvertView()  
  66.     {  
  67.         return mConvertView;  
  68.     }  
  69.   
  70.       
  71.   
  72. }  
package com.example.zhy_baseadapterhelper;import android.content.Context;import android.util.Log;import android.util.SparseArray;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;public class ViewHolder{    private final SparseArray<View> mViews;    private View mConvertView;    private ViewHolder(Context context, ViewGroup parent, int layoutId,            int position)    {        this.mViews = new SparseArray<View>();        mConvertView = LayoutInflater.from(context).inflate(layoutId, parent,                false);        //setTag        mConvertView.setTag(this);    }    /**     * 拿到一个ViewHolder对象     * @param context     * @param convertView     * @param parent     * @param layoutId     * @param position     * @return     */    public static ViewHolder get(Context context, View convertView,            ViewGroup parent, int layoutId, int position)    {        if (convertView == null)        {            return new ViewHolder(context, parent, layoutId, position);        }        return (ViewHolder) convertView.getTag();    }    /**     * 通过控件的Id获取对于的控件,如果没有则加入views     * @param viewId     * @return     */    public <T extends View> T getView(int viewId)    {        View view = mViews.get(viewId);        if (view == null)        {            view = mConvertView.findViewById(viewId);            mViews.put(viewId, view);        }        return (T) view;    }    public View getConvertView()    {        return mConvertView;    }}


与传统的ViewHolder不同,我们使用了一个SparseArray<View>用于存储与之对于的convertView的所有的控件,当需要拿这些控件时,通过getView(id)进行获取;

下面看使用该ViewHolder的MyAdapter;

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. @Override  
  2.     public View getView(int position, View convertView, ViewGroup parent)  
  3.     {  
  4.         //实例化一个viewHolder  
  5.         ViewHolder viewHolder = ViewHolder.get(mContext, convertView, parent,  
  6.                 R.layout.item_single_str, position);  
  7.         //通过getView获取控件  
  8.         TextView tv = viewHolder.getView(R.id.id_tv_title);  
  9.         //使用  
  10.         tv.setText(mDatas.get(position));  
  11.         return viewHolder.getConvertView();  
  12.     }  
@Override    public View getView(int position, View convertView, ViewGroup parent)    {        //实例化一个viewHolder        ViewHolder viewHolder = ViewHolder.get(mContext, convertView, parent,                R.layout.item_single_str, position);        //通过getView获取控件        TextView tv = viewHolder.getView(R.id.id_tv_title);        //使用        tv.setText(mDatas.get(position));        return viewHolder.getConvertView();    }

只看getView,其他方法都一样;首先调用ViewHolder的get方法,如果convertView为null,new一个ViewHolder实例,通过使用mInflater.inflate加载布局,然后new一个SparseArray用于存储View,最后setTag(this);

如果存在那么直接getTag

最后通过getView(id)获取控件,如果存在则直接返回,否则调用findViewById,返回存储,返回。

好了,一个通用的ViewHolder写好了,以后一个项目几十个Adapter一个ViewHolder直接hold住全场~~大家可以省点时间斗个小地主了~~

4、打造通用的Adapter

有了通用的ViewHolder大家肯定不能满足,怎么也得省出dota的时间,人在塔在~~

下面看如何打造一个通过的Adapter,我们叫做CommonAdapter

继续分析,Adapter一般需要保持一个List对象,存储一个Bean的集合,不同的ListView,Bean肯定是不同的,这个CommonAdapter肯定需要支持泛型,内部维持一个List<T>,就解决我们的问题了;

于是我们初步打造我们的CommonAdapter

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. package com.example.zhy_baseadapterhelper;  
  2.   
  3. import java.util.List;  
  4.   
  5. import android.content.Context;  
  6. import android.view.LayoutInflater;  
  7. import android.view.View;  
  8. import android.view.ViewGroup;  
  9. import android.widget.BaseAdapter;  
  10. import android.widget.TextView;  
  11.   
  12. public abstract class CommonAdapter<T> extends BaseAdapter  
  13. {  
  14.     protected LayoutInflater mInflater;  
  15.     protected Context mContext;  
  16.     protected List<T> mDatas;  
  17.   
  18.     public CommonAdapter(Context context, List<T> mDatas)  
  19.     {  
  20.         mInflater = LayoutInflater.from(context);  
  21.         this.mContext = context;  
  22.         this.mDatas = mDatas;  
  23.     }  
  24.   
  25.     @Override  
  26.     public int getCount()  
  27.     {  
  28.         return mDatas.size();  
  29.     }  
  30.   
  31.     @Override  
  32.     public Object getItem(int position)  
  33.     {  
  34.         return mDatas.get(position);  
  35.     }  
  36.   
  37.     @Override  
  38.     public long getItemId(int position)  
  39.     {  
  40.         return position;  
  41.     }  
  42.   
  43. }  
package com.example.zhy_baseadapterhelper;import java.util.List;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;public abstract class CommonAdapter<T> extends BaseAdapter{    protected LayoutInflater mInflater;    protected Context mContext;    protected List<T> mDatas;    public CommonAdapter(Context context, List<T> mDatas)    {        mInflater = LayoutInflater.from(context);        this.mContext = context;        this.mDatas = mDatas;    }    @Override    public int getCount()    {        return mDatas.size();    }    @Override    public Object getItem(int position)    {        return mDatas.get(position);    }    @Override    public long getItemId(int position)    {        return position;    }}
我们的CommonAdapter依然是一个抽象类,除了getView以外我们把其他的代码都实现了,这样的话,在使用我们的Adapter只要实现一个getView,然后getView里面再使用我们打造的通过的ViewHolder是不是感觉还不错~

现在我们的MyAdapter是这样的:

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. package com.example.zhy_baseadapterhelper;  
  2.   
  3. import java.util.List;  
  4.   
  5. import android.content.Context;  
  6. import android.view.View;  
  7. import android.view.ViewGroup;  
  8. import android.widget.TextView;  
  9.   
  10. public class MyAdapter<T> extends CommonAdapter<T>  
  11. {  
  12.     public MyAdapter(Context context, List<T> mDatas)  
  13.     {  
  14.         super(context, mDatas);  
  15.     }  
  16.   
  17.     @Override  
  18.     public View getView(int position, View convertView, ViewGroup parent)  
  19.     {  
  20.         ViewHolder viewHolder = ViewHolder.get(mContext, convertView, parent,  
  21.                 R.layout.item_single_str, position);  
  22.         TextView mTitle = viewHolder.getView(R.id.id_tv_title);  
  23.         mTitle.setText((String) mDatas.get(position));  
  24.         return viewHolder.getConvertView();  
  25.     }  
  26.   
  27. }  
package com.example.zhy_baseadapterhelper;import java.util.List;import android.content.Context;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;public class MyAdapter<T> extends CommonAdapter<T>{    public MyAdapter(Context context, List<T> mDatas)    {        super(context, mDatas);    }    @Override    public View getView(int position, View convertView, ViewGroup parent)    {        ViewHolder viewHolder = ViewHolder.get(mContext, convertView, parent,                R.layout.item_single_str, position);        TextView mTitle = viewHolder.getView(R.id.id_tv_title);        mTitle.setText((String) mDatas.get(position));        return viewHolder.getConvertView();    }}

所有的代码加起来也就10行左右,是不是神清气爽~~稍等,我先去dota一把~

但是我们是否就这样满足了呢?显然还可以简化。

5、进一步铸造

注意我们的getView里面的代码,虽然只有4行,但是我觉得所有的Adapter的

第一行(ViewHolder viewHolder = getViewHolder(position, convertView,parent);)和

最后一行:return viewHolder.getConvertView();一定是一样的。

那么我们可以这样做:我们把第一行和最后一行写死,把中间变化的部分抽取出来,这不就是OO的设计原则嘛。现在CommonAdapter是这样的:

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. package com.example.zhy_baseadapterhelper;  
  2.   
  3. import java.util.List;  
  4.   
  5. import android.content.Context;  
  6. import android.view.LayoutInflater;  
  7. import android.view.View;  
  8. import android.view.ViewGroup;  
  9. import android.widget.BaseAdapter;  
  10.   
  11. public abstract class CommonAdapter<T> extends BaseAdapter  
  12. {  
  13.     protected LayoutInflater mInflater;  
  14.     protected Context mContext;  
  15.     protected List<T> mDatas;  
  16.     protected final int mItemLayoutId;  
  17.   
  18.     public CommonAdapter(Context context, List<T> mDatas, int itemLayoutId)  
  19.     {  
  20.         this.mContext = context;  
  21.         this.mInflater = LayoutInflater.from(mContext);  
  22.         this.mDatas = mDatas;  
  23.         this.mItemLayoutId = itemLayoutId;  
  24.     }  
  25.   
  26.     @Override  
  27.     public int getCount()  
  28.     {  
  29.         return mDatas.size();  
  30.     }  
  31.   
  32.     @Override  
  33.     public T getItem(int position)  
  34.     {  
  35.         return mDatas.get(position);  
  36.     }  
  37.   
  38.     @Override  
  39.     public long getItemId(int position)  
  40.     {  
  41.         return position;  
  42.     }  
  43.   
  44.     @Override  
  45.     public View getView(int position, View convertView, ViewGroup parent)  
  46.     {  
  47.         final ViewHolder viewHolder = getViewHolder(position, convertView,  
  48.                 parent);  
  49.         convert(viewHolder, getItem(position));  
  50.         return viewHolder.getConvertView();  
  51.   
  52.     }  
  53.   
  54.     public abstract void convert(ViewHolder helper, T item);  
  55.   
  56.     private ViewHolder getViewHolder(int position, View convertView,  
  57.             ViewGroup parent)  
  58.     {  
  59.         return ViewHolder.get(mContext, convertView, parent, mItemLayoutId,  
  60.                 position);  
  61.     }  
  62.   
  63. }  
package com.example.zhy_baseadapterhelper;import java.util.List;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;public abstract class CommonAdapter<T> extends BaseAdapter{    protected LayoutInflater mInflater;    protected Context mContext;    protected List<T> mDatas;    protected final int mItemLayoutId;    public CommonAdapter(Context context, List<T> mDatas, int itemLayoutId)    {        this.mContext = context;        this.mInflater = LayoutInflater.from(mContext);        this.mDatas = mDatas;        this.mItemLayoutId = itemLayoutId;    }    @Override    public int getCount()    {        return mDatas.size();    }    @Override    public T getItem(int position)    {        return mDatas.get(position);    }    @Override    public long getItemId(int position)    {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent)    {        final ViewHolder viewHolder = getViewHolder(position, convertView,                parent);        convert(viewHolder, getItem(position));        return viewHolder.getConvertView();    }    public abstract void convert(ViewHolder helper, T item);    private ViewHolder getViewHolder(int position, View convertView,            ViewGroup parent)    {        return ViewHolder.get(mContext, convertView, parent, mItemLayoutId,                position);    }}

对外公布了一个convert方法,并且还把viewHolder和本Item对于的Bean对象给传出去,现在convert方法里面需要干嘛呢?

通过ViewHolder把View找到,通过Item设置值;

现在我觉得代码简化到这样,我已经不需要单独写一个Adapter了,直接MainActivity匿名内部类走起~

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. @Override  
  2.     protected void onCreate(Bundle savedInstanceState)  
  3.     {  
  4.         super.onCreate(savedInstanceState);  
  5.         setContentView(R.layout.activity_main);  
  6.         mListView = (ListView) findViewById(R.id.id_lv_main);  
  7.   
  8.         //设置适配器  
  9.         mListView.setAdapter(mAdapter = new CommonAdapter<String>(  
  10.                 getApplicationContext(), mDatas, R.layout.item_single_str)  
  11.         {  
  12.             @Override  
  13.             public void convert(ViewHolder c, String item)  
  14.             {  
  15.                 TextView view = viewHolder.getView(R.id.id_tv_title);  
  16.                 view.setText(item);  
  17.             }  
  18.   
  19.         });  
  20.   
  21.     }  
@Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mListView = (ListView) findViewById(R.id.id_lv_main);        //设置适配器        mListView.setAdapter(mAdapter = new CommonAdapter<String>(                getApplicationContext(), mDatas, R.layout.item_single_str)        {            @Override            public void convert(ViewHolder c, String item)            {                TextView view = viewHolder.getView(R.id.id_tv_title);                view.setText(item);            }        });    }

可以看到效果咋样,不错吧。你觉得还能简化么?我觉得还能改善。

6、Adapter最后的封魔

我们现在在convertView里面需要这样:

@Override
public void convert(ViewHolder viewHolder, String item)
{
TextView view = viewHolder.getView(R.id.id_tv_title);
view.setText(item);
}

我们细想一下,其实布局里面的View常用也就那么几种:ImageView,TextView,Button,CheckBox等等;

那么我觉得ViewHolder还可以封装一些常用的方法,比如setText(id,String);setImageResource(viewId, resId);setImageBitmap(viewId, bitmap);

那么现在ViewHolder是:

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. package com.example.zhy_baseadapterhelper;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Bitmap;  
  5. import android.util.SparseArray;  
  6. import android.view.LayoutInflater;  
  7. import android.view.View;  
  8. import android.view.ViewGroup;  
  9. import android.widget.ImageView;  
  10. import android.widget.TextView;  
  11.   
  12. import com.example.zhy_baseadapterhelper.ImageLoader.Type;  
  13.   
  14. public class ViewHolder  
  15. {  
  16.     private final SparseArray<View> mViews;  
  17.     private int mPosition;  
  18.     private View mConvertView;  
  19.   
  20.     private ViewHolder(Context context, ViewGroup parent, int layoutId,  
  21.             int position)  
  22.     {  
  23.         this.mPosition = position;  
  24.         this.mViews = new SparseArray<View>();  
  25.         mConvertView = LayoutInflater.from(context).inflate(layoutId, parent,  
  26.                 false);  
  27.         // setTag  
  28.         mConvertView.setTag(this);  
  29.     }  
  30.   
  31.     /** 
  32.      * 拿到一个ViewHolder对象 
  33.      *  
  34.      * @param context 
  35.      * @param convertView 
  36.      * @param parent 
  37.      * @param layoutId 
  38.      * @param position 
  39.      * @return 
  40.      */  
  41.     public static ViewHolder get(Context context, View convertView,  
  42.             ViewGroup parent, int layoutId, int position)  
  43.     {  
  44.         if (convertView == null)  
  45.         {  
  46.             return new ViewHolder(context, parent, layoutId, position);  
  47.         }  
  48.         return (ViewHolder) convertView.getTag();  
  49.     }  
  50.   
  51.     public View getConvertView()  
  52.     {  
  53.         return mConvertView;  
  54.     }  
  55.   
  56.     /** 
  57.      * 通过控件的Id获取对于的控件,如果没有则加入views 
  58.      *  
  59.      * @param viewId 
  60.      * @return 
  61.      */  
  62.     public <T extends View> T getView(int viewId)  
  63.     {  
  64.         View view = mViews.get(viewId);  
  65.         if (view == null)  
  66.         {  
  67.             view = mConvertView.findViewById(viewId);  
  68.             mViews.put(viewId, view);  
  69.         }  
  70.         return (T) view;  
  71.     }  
  72.   
  73.     /** 
  74.      * 为TextView设置字符串 
  75.      *  
  76.      * @param viewId 
  77.      * @param text 
  78.      * @return 
  79.      */  
  80.     public ViewHolder setText(int viewId, String text)  
  81.     {  
  82.         TextView view = getView(viewId);  
  83.         view.setText(text);  
  84.         return this;  
  85.     }  
  86.   
  87.     /** 
  88.      * 为ImageView设置图片 
  89.      *  
  90.      * @param viewId 
  91.      * @param drawableId 
  92.      * @return 
  93.      */  
  94.     public ViewHolder setImageResource(int viewId, int drawableId)  
  95.     {  
  96.         ImageView view = getView(viewId);  
  97.         view.setImageResource(drawableId);  
  98.   
  99.         return this;  
  100.     }  
  101.   
  102.     /** 
  103.      * 为ImageView设置图片 
  104.      *  
  105.      * @param viewId 
  106.      * @param drawableId 
  107.      * @return 
  108.      */  
  109.     public ViewHolder setImageBitmap(int viewId, Bitmap bm)  
  110.     {  
  111.         ImageView view = getView(viewId);  
  112.         view.setImageBitmap(bm);  
  113.         return this;  
  114.     }  
  115.   
  116.     /** 
  117.      * 为ImageView设置图片 
  118.      *  
  119.      * @param viewId 
  120.      * @param drawableId 
  121.      * @return 
  122.      */  
  123.     public ViewHolder setImageByUrl(int viewId, String url)  
  124.     {  
  125.         ImageLoader.getInstance(3, Type.LIFO).loadImage(url,  
  126.                 (ImageView) getView(viewId));  
  127.         return this;  
  128.     }  
  129.   
  130.     public int getPosition()  
  131.     {  
  132.         return mPosition;  
  133.     }  
  134.   
  135. }  
package com.example.zhy_baseadapterhelper;import android.content.Context;import android.graphics.Bitmap;import android.util.SparseArray;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.TextView;import com.example.zhy_baseadapterhelper.ImageLoader.Type;public class ViewHolder{    private final SparseArray<View> mViews;    private int mPosition;    private View mConvertView;    private ViewHolder(Context context, ViewGroup parent, int layoutId,            int position)    {        this.mPosition = position;        this.mViews = new SparseArray<View>();        mConvertView = LayoutInflater.from(context).inflate(layoutId, parent,                false);        // setTag        mConvertView.setTag(this);    }    /**     * 拿到一个ViewHolder对象     *      * @param context     * @param convertView     * @param parent     * @param layoutId     * @param position     * @return     */    public static ViewHolder get(Context context, View convertView,            ViewGroup parent, int layoutId, int position)    {        if (convertView == null)        {            return new ViewHolder(context, parent, layoutId, position);        }        return (ViewHolder) convertView.getTag();    }    public View getConvertView()    {        return mConvertView;    }    /**     * 通过控件的Id获取对于的控件,如果没有则加入views     *      * @param viewId     * @return     */    public <T extends View> T getView(int viewId)    {        View view = mViews.get(viewId);        if (view == null)        {            view = mConvertView.findViewById(viewId);            mViews.put(viewId, view);        }        return (T) view;    }    /**     * 为TextView设置字符串     *      * @param viewId     * @param text     * @return     */    public ViewHolder setText(int viewId, String text)    {        TextView view = getView(viewId);        view.setText(text);        return this;    }    /**     * 为ImageView设置图片     *      * @param viewId     * @param drawableId     * @return     */    public ViewHolder setImageResource(int viewId, int drawableId)    {        ImageView view = getView(viewId);        view.setImageResource(drawableId);        return this;    }    /**     * 为ImageView设置图片     *      * @param viewId     * @param drawableId     * @return     */    public ViewHolder setImageBitmap(int viewId, Bitmap bm)    {        ImageView view = getView(viewId);        view.setImageBitmap(bm);        return this;    }    /**     * 为ImageView设置图片     *      * @param viewId     * @param drawableId     * @return     */    public ViewHolder setImageByUrl(int viewId, String url)    {        ImageLoader.getInstance(3, Type.LIFO).loadImage(url,                (ImageView) getView(viewId));        return this;    }    public int getPosition()    {        return mPosition;    }}

现在的MainActivity只需要这么写:

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. mAdapter = new CommonAdapter<String>(getApplicationContext(),  
  2.                 R.layout.item_single_str, mDatas)  
  3.         {  
  4.             @Override  
  5.             protected void convert(ViewHolder viewHolder, String item)  
  6.             {  
  7.                 viewHolder.setText(R.id.id_tv_title, item);  
  8.             }  
  9.         };  
mAdapter = new CommonAdapter<String>(getApplicationContext(),                R.layout.item_single_str, mDatas)        {            @Override            protected void convert(ViewHolder viewHolder, String item)            {                viewHolder.setText(R.id.id_tv_title, item);            }        };

convertView里面只要一行代码了~~~

好了,到此我们的通用的Adapter已经一步一步铸造完毕~咋样,以后写项目省下来的时间是不是可以陪我切磋dota了(ps:11昵称:血魔哥404)~~

注:关于ViewHolder里面的setText,setImageResource这类的方法,大家可以在使用的过程中不断的完善,今天发现这个控件可以这么设置值,好,放进去;时间长了,基本就完善了。还有那个ImageLoader是我另一篇博客里的,大家可以使用UIL,Volley或者自己写个图片加载器;

7、实践

说了这么多,还是得拿出来让我们的实践检验检验,顺便来几张套图,俗话说,没图没正相。

1、我们的实例代码的图是这样的:

关于Adapter和ViewHolder的代码是这样的:

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. // 设置适配器  
  2.         mListView.setAdapter(mAdapter = new CommonAdapter<String>(  
  3.                 getApplicationContext(), mDatas, R.layout.item_single_str)  
  4.         {  
  5.             @Override  
  6.             public void convert(ViewHolder helper, String item)  
  7.             {  
  8.                 helper.setText(R.id.id_tv_title,item);  
  9.             }  
  10.   
  11.         });  
// 设置适配器        mListView.setAdapter(mAdapter = new CommonAdapter<String>(                getApplicationContext(), mDatas, R.layout.item_single_str)        {            @Override            public void convert(ViewHolder helper, String item)            {                helper.setText(R.id.id_tv_title,item);            }        });

哎哟,我是不是只要贴一行;

2、来个复杂点的布局

[html] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. <?xml version=“1.0” encoding=“utf-8”?>  
  2. <RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”  
  3.     android:layout_width=“match_parent”  
  4.     android:layout_height=“wrap_content”  
  5.     android:background=“#ffffff”  
  6.     android:orientation=“vertical”  
  7.     android:padding=“10dp” >  
  8.   
  9.     <TextView  
  10.         android:id=“@+id/tv_title”  
  11.         android:layout_width=“match_parent”  
  12.         android:layout_height=“wrap_content”  
  13.         android:singleLine=“true”  
  14.         android:text=“红色钱包”  
  15.         android:textSize=“16sp”  
  16.         android:textColor=“#444444” >  
  17.     </TextView>  
  18.   
  19.     <TextView  
  20.         android:id=“@+id/tv_describe”  
  21.         android:layout_width=“match_parent”  
  22.         android:layout_height=“wrap_content”  
  23.         android:layout_below=“@id/tv_title”  
  24.         android:layout_marginTop=“10dp”  
  25.         android:maxLines=“2”  
  26.         android:minLines=“1”  
  27.         android:text=“周三早上丢失了红色钱包,在食堂二楼”  
  28.         android:textColor=“#898989”  
  29.         android:textSize=“16sp” >  
  30.     </TextView>  
  31.   
  32.     <TextView  
  33.         android:id=“@+id/tv_time”  
  34.         android:layout_width=“wrap_content”  
  35.         android:layout_height=“wrap_content”  
  36.         android:layout_below=“@id/tv_describe”  
  37.         android:layout_marginTop=“10dp”  
  38.         android:text=“20130240122”  
  39.         android:textColor=“#898989”  
  40.         android:textSize=“12sp” >  
  41.     </TextView>  
  42.   
  43.     <TextView  
  44.         android:id=“@+id/tv_phone”  
  45.         android:layout_width=“wrap_content”  
  46.         android:layout_height=“wrap_content”  
  47.         android:layout_alignParentRight=“true”  
  48.         android:layout_below=“@id/tv_describe”  
  49.         android:layout_marginTop=“10dp”  
  50.         android:background=“#5cbe6c”  
  51.         android:drawableLeft=“@drawable/icon_photo”  
  52.         android:drawablePadding=“5dp”  
  53.         android:paddingBottom=“3dp”  
  54.         android:paddingLeft=“5dp”  
  55.         android:paddingRight=“5dp”  
  56.         android:paddingTop=“3dp”  
  57.         android:text=“138024249542”  
  58.         android:textColor=“#ffffff”  
  59.         android:textSize=“12sp” >  
  60.     </TextView>  
  61.   
  62. </RelativeLayout>  
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:background="#ffffff"    android:orientation="vertical"    android:padding="10dp" >    <TextView        android:id="@+id/tv_title"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:singleLine="true"        android:text="红色钱包"        android:textSize="16sp"        android:textColor="#444444" >    </TextView>    <TextView        android:id="@+id/tv_describe"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_below="@id/tv_title"        android:layout_marginTop="10dp"        android:maxLines="2"        android:minLines="1"        android:text="周三早上丢失了红色钱包,在食堂二楼"        android:textColor="#898989"        android:textSize="16sp" >    </TextView>    <TextView        android:id="@+id/tv_time"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/tv_describe"        android:layout_marginTop="10dp"        android:text="20130240122"        android:textColor="#898989"        android:textSize="12sp" >    </TextView>    <TextView        android:id="@+id/tv_phone"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentRight="true"        android:layout_below="@id/tv_describe"        android:layout_marginTop="10dp"        android:background="#5cbe6c"        android:drawableLeft="@drawable/icon_photo"        android:drawablePadding="5dp"        android:paddingBottom="3dp"        android:paddingLeft="5dp"        android:paddingRight="5dp"        android:paddingTop="3dp"        android:text="138024249542"        android:textColor="#ffffff"        android:textSize="12sp" >    </TextView></RelativeLayout>

效果图是这样的:


布局是不是挺复杂的了~~

但是代码是这样的:

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. // 设置适配器  
  2.         mListView.setAdapter(mAdapter = new CommonAdapter<Bean>(  
  3.                 getApplicationContext(), mDatas, R.layout.item_list)  
  4.         {  
  5.             @Override  
  6.             public void convert(ViewHolder helper, Bean item)  
  7.             {  
  8.                 helper.setText(R.id.tv_title, item.getTitle());  
  9.                 helper.setText(R.id.tv_describe, item.getDesc());  
  10.                 helper.setText(R.id.tv_phone, item.getPhone());  
  11.                 helper.setText(R.id.tv_time, item.getTime());  
  12.                   
  13. //              helper.getView(R.id.tv_title).setOnClickListener(l)  
  14.             }  
  15.   
  16.         });  
// 设置适配器        mListView.setAdapter(mAdapter = new CommonAdapter<Bean>(                getApplicationContext(), mDatas, R.layout.item_list)        {            @Override            public void convert(ViewHolder helper, Bean item)            {                helper.setText(R.id.tv_title, item.getTitle());                helper.setText(R.id.tv_describe, item.getDesc());                helper.setText(R.id.tv_phone, item.getPhone());                helper.setText(R.id.tv_time, item.getTime());//              helper.getView(R.id.tv_title).setOnClickListener(l)            }        });

从一个字符串的布局到这样的布局,Adapter加ViewHolder的改变就这么多,加起来3行左右代码~~~


到此,Android 快速开发系列 打造万能的ListView GridView 适配器结束;


最后给大家推荐一个gitHub项目:https://github.com/JoanZapata/base-adapter-helper ,这个项目所做的,和我上面写的基本一致。

还有上面的布局文件来自网络,感谢Bmob的提供~

好了,我要去快乐的玩耍了~~


以下为最新更新==>

添加了多种Item类型的支持,源码地址:https://github.com/hongyangAndroid/base-adapter . 









1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 花甲生的吃了怎么办 别人告我欠他钱怎么办 实习手册没有公司的印章怎么办? 家长管的太严怎么办 对于老公沉迷于股票怎么办 月经期吃了香瓜怎么办 月经漏到内裤上怎么办 上班没时间养狗怎么办 宝宝呼吸道感染反复发烧怎么办 熬夜后头晕想吐怎么办 生气后全身无力酸痛怎么办? 久坐导致的腰疼怎么办 削土豆手变黑了怎么办 熬夜后头痛眼痛怎么办 孩子毎天通宵游戏怎么办 熬夜写作业困了怎么办 三十多岁白头发越来越多怎么办 AI界面字体太小怎么办 睡不着怎么办躺倒床上脑子混乱 作息规律不正常夜里睡不着怎么办 作息不规律引起身体痒怎么办 在大学里好无聊怎么办 开会时间通知错了怎么办 商场要求商户变更位置怎么办 怀孕初期症状小腹痛怎么办 1岁半宝宝吃夜奶怎么办 戒奶宝宝不喝奶粉怎么办 2岁半宝宝老晚睡怎么办 老是熬夜然后想调生物钟怎么办 一个月宝宝睡眠不好怎么办 个人怎么办一清pos机 社保到退休年龄未交满15年怎么办 退休时社保没交满15时怎么办 单位不支付病假工资怎么办 一年级学生上课注意力不集中怎么办 一年级学生的理解能力差怎么办 一年级学生学习太差怎么办 宝宝屁眼破皮怎么办啊 九个月婴儿不爱喝奶怎么办 十一个月婴儿发烧怎么办 四个月宝宝睡不踏实怎么办