关于Adapter和ViewHolder的另类写法

本文提出一种新的ViewHolder模式实现方法,通过自定义BaseHolder类简化代码结构,提高代码复用性和维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网上已经有一些关于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后写法变得超级简便。

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值