关于Adapter和ViewHolder的另类写法

来源:互联网 发布:winxp系统修复软件 编辑:程序博客网 时间:2024/05/21 13:59

网上已经有一些关于ViewHolder的另类写法,但如果item里控件稍多起来的话,整个adpter类还是会稍显冗余。于是接下来为大家介绍另一种另类的写法。

         项目就是对一个ListView填充数据。

         ListView优化里,ViewHolder类的重要性不言而喻,寻常ViewHolder类写法的弊端就不说了,大家都懂。

         这里先自定义一个BaseHolder类,代码如下:

/** * @des 提供视图,绑定数据*/public abstract class BaseHolder<HOLDERBEANTYPE> {    public View mHolderView;        //提供的视图    private HOLDERBEANTYPE mData;   //数据,注意:这里的数据是List集合里的子数据    public Context mContext;        //上下文    public BaseHolder(Context context){        mContext = context;        //初始化视图        mHolderView = initHolderView();        //将视图与holder类进行绑定        mHolderView.setTag(this);    }    /**     * @des   接收数据,与视图进行绑定     * @param data List集合里的子数据,即每一个视图里需要填充的数据     */    public void setDataAndRefreshHolderView(HOLDERBEANTYPE data){        mData = data;        //与视图进行绑定        refreshHolderView(data);    }    /**     * @des  与视图进行绑定,交给子类去实现     */    protected abstract void refreshHolderView(HOLDERBEANTYPE data);    /**     * @des   初始化数据,交给子类去实现     * @return     */    public abstract View initHolderView();}


仅仅是一个BaseHolder类并不能明确需要提供的视图和数据绑定等操作,所以,接下来,就根据具体的item.xml文件来提供特定的holder类:代码如下:

/** * @des 提供视图;接收数据;视图和数据的绑定 */public class ChildHolder extends BaseHolder<String> {    //子类holder,到这里就已经知道自己到传递的数据是什么类型了,这里就用String类作为演示    private TextView mTextView;    public ChildHolder(Context context) {        super(context);    }    /**     * @return     * @des 初始化视图     */    @Override    public View initHolderView() {        //这里的item.xml文件里只添加了一个TextView,布局比较简单就不给出代码了。        View holderView = View.inflate(mContext, R.layout.item, null);        mTextView = (TextView) holderView.findViewById(R.id.item_text);        return holderView;    }    /**     * @des 进行数据与视图的绑定     */    @Override    protected void refreshHolderView(String data) {        mTextView.setText(data);    }}

到此,整个ViewHolder类的准备工作就已经完成了,是否可以直接在Adapter适配器里面使用了呢?当然可以,但如果直接使用BaseAdapter类,我们还得重写getView、getItem、getItemId和getCount等方法。

这里,我们再进一步,对BaseAdapter类进行继承抽取,代码如下:

/** * @des 这个类主要对BaseAdapter的除getView的其三个方法 进行复写 */public abstract class MyAdapter<ITEMBEANTYPE> extends BaseAdapter {        public List<ITEMBEANTYPE> mDatas;    //要填充的数据,这里的数据是全部数据的集合    public MyAdapter(List<ITEMBEANTYPE> datas) {        mDatas = datas;    }    @Override    public int getCount() {        if (mDatas != null) {            return mDatas.size();        }        return 0;    }    @Override    public Object getItem(int position) {        if (mDatas != null) {            return mDatas.get(position);        }        return null;    }    @Override    public long getItemId(int position) {        return position;    }}

上面的MyAdapter只是对三个方法进行了重写,接下来我们去重写getView方法,这里是重点,大家细细看,代码如下:

/** * @des 针对getView方法进行复写 */public abstract class SuperAdapter<ITEMBEANTYPE> extends MyAdapter {    public SuperAdapter(List<ITEMBEANTYPE> datas) {        super(datas);    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        BaseHolder baseHolder;        if (convertView == null) {            //创建holder类            baseHolder = getSpecialHolder();        } else {            //如果不为空,就直接获取,至于这里为什么能直接获取,是因为BaseHolder类的构造方法里已经对视图进行了绑定            baseHolder = (BaseHolder) convertView.getTag();        }        //获取视图        View holderView = baseHolder.mHolderView;        //进行视图和数据的绑定        baseHolder.setDataAndRefreshHolderView(mDatas.get(position));        return holderView;    }    /**     * @return     * @des 获取具体的holder类,交给子类去实现     */    public abstract BaseHolder getSpecialHolder();}


至些,一切的准备工作已经完成,我们可以直接去使用了:

 

public class MainActivity extends AppCompatActivity {    private ListView mListview;    private List<String> mDatas;       //要填充的数据    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //这里为了方便演示,直接模拟了数据        mDatas = new ArrayList<String>();        for (int i = 0; i < 100; i++) {            mDatas.add(i + "");        }        mListview = (ListView) findViewById(R.id.main_listview);        mListview.setAdapter(new MainListViewAdapter(mDatas));    }    public class MainListViewAdapter extends SuperAdapter {        //通过构造方法传递数据        public MainListViewAdapter(List<String> datas) {            super(datas);        }        //返回相应的holder子类        @Override        public BaseHolder getSpecialHolder() {            return new ChildHolder(MainActivity.this);        }    }}

直接运行就能出效果了。

这里抽取的比较多,看似比直接使用BaseAdapter还要复杂得多,但在之后的使用中你只需要去写一个相应的holder子类就可以了,而且继承SuperAdapter后写法变得超级简便。

更重要的一点,这种写法对于之后代码的维护非常的有利。

(初写博文,写的不尽详细请见谅,如有改进之处,望大家不吝建议。)

1 0
原创粉丝点击