ListView的“终极优化”,打造你的万能适配器

本篇文章你会了解以下内容:


1、抽取ViewHolder,实现优化第一步

2、抽取公共Adapter,告别冗余方法

3、控件直接赋值,让Adapter再次优化


执笔不易,觉得不错,请转发分享(更多Android文章,还请关注左侧栏中我的公众号)。


ListView不得不说是Android开发当中出现率相当高的一个控件,什么资讯列表,联系人列表,消息列表等等,无不有它的身影存在。既然项目中有太多的地方会用到它,传统的代码逻辑我们是怎么使用的呢?每写一个ListView,都要去写一个Adapter类,一个ViewHolder类,这几乎是我们必须要操作的,以致于有太多太多的冗余代码,让我们感到真的不厌其烦,一个两个还可以,十个八个,就真的有点太崩溃了,不仅代码繁琐,还会占用内存,为了解决这样的一个问题,下面就要开始对其抽取优化,代码之间从上到下进行衔接,不要跳过看啊。


1、抽取ViewHolder,实现优化第一步


我们知道正常的ViewHolder,会在Adapter的getView方法里去操作很多事情,创建实例,赋值控件,setTag和getTag等,如下代码所示,是我们最常用的模式,这里我只用了两个控件,其实开发中有很多的View,对ViewHolder的优化,就是把这些代码封装进行抽取。

@Override
public View getView(int positionView convertViewViewGroup parent) {
    View view;
    
ViewHolder viewHolder;
    if 
(convertView == null) {
        view = View.inflate(mContextR.layout.item_view, null);
        
viewHolder = new ViewHolder();
        
viewHolder.tvTitle = (TextView) view.findViewById(R.id.tv_title);
        
viewHolder.tvContent = (TextView) view.findViewById(R.id.tv_content);
        
view.setTag(viewHolder);
    
else {
        view = convertView;
        
viewHolder = (ViewHolder) view.getTag();
    
}

viewHolder.tvTitle.setText(mDatas.get(position).getTitle());

viewHolder.tvContent.setText(mDatas.get(position).getContent());


    return view;
}

private static class ViewHolder {
    TextView tvTitletvContent;
}


自定义一个ViewHolder类,实现构造方法,既然要实现对以上的代码进行一个抽取,那么getView里的参数,ViewHolder类大部分都需要用到,在ViewHolder类中,写一个静态方法,用于获取ViewHolder,其判断逻辑和以上代码思路一致,convertView若不存在就去创建ViewHolder,若存在就复用。


public static ViewHolder getViewHolder(Context context, int position,
                                     
View convertViewViewGroup parent, int layoutId) {
    if (convertView == null) {
        return new ViewHolder(contextpositionparentlayoutId);
    
else {
        ViewHolder viewHolder = (ViewHolder) convertView.getTag();
        
viewHolder.mPosition = position;
        return 
viewHolder;
    
}
}


实现其构造方法,用于convertView不存在时进行对其实例:


private SparseArray<View> mView;
private int mPosition;
private View mConvertView;


public ViewHolder(Context context, int positionViewGroup parent, int layoutId) {
    mPosition = position;
    
mView new SparseArray<View>();
    
mConvertView = View.inflate(contextlayoutId, null);
    
mConvertView.setTag(this);
}


mView是用于存储各个控件View,在这里为什么要用SparseArray而不用Map,我们可以去查看下源码,其实对于键为int类型,SparseArray要比map更加有效的使用内存。


mPosition是记录索引位置。


mConverView就是创建的View对象,注意看上述代码,它是在convertView为null的情况下,才去创建的。


写一个方法,用于通过ViewHolder来获取各个控件:


public <extends View> getView(int layoutId) {
    View view = mView.get(layoutId);
    if 
(view == null) {
        view = getmConvertView().findViewById(layoutId);
        
mView.put(layoutIdview);
    
}
    return (T) view;
}


再写一个获取layout的方法:


public View getmConvertView() {
    
return mConvertView;
}


经过以上代码,对于ViewHolder,我们基本上就抽取完成了,回过来,我们再看adapter里的getView方法(注意,原来adapter里的ViewHolder类可以对其删除),是不是一下整洁了许多。


@Override
public View getView(int positionView convertViewViewGroup parent) {
    ViewHolder viewHolder=ViewHolder.getViewHoder(mContext,position,
            
convertView,parent,R.layout.item_view);
    
((TextView)viewHolder.getView(R.id.tv_title)).
            setText(mDatas.get(position).getTitle());
    
((TextView)viewHolder.getView(R.id.tv_content)).
            setText(mDatas.get(position).getContent());
    return 
viewHolder.getmConvertView();
}



2、抽取公共Adapter,告别冗余方法


ViewHolder抽取完之后,省去了太多的代码,但是我们会发现Adapter里除了getView方法,其它三个也是重复的,那么接下来,我们就对Adapter进行抽取优化,新建一个万能的Adapter类,继承于BaseAdapter,记住要是抽象的,把getView方法设成抽象方法,这样其它Adapter继承这个万能Adapter,只需要重写getView方法即可。


public abstract class UniversalAdapter<Textends BaseAdapter {
    protected List<TmDatas;
    protected 
Context context;
    private int 
layoutId;

    public 
UniversalAdapter(Context contextList<T> mDatas, int layoutId) {
        this.mDatas = mDatas;
        this
.context = context;
        this
.layoutId = layoutId;
    
}

    @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 abstract View getView(int positionView convertViewViewGroup parent);
}



在上述代码中,细心的同志的可能看到了,实现其构造方法时,我传入了一个layoutId,其实就是一个XML资源,引入它,说白了,在getView方法里我连 ViewHolder viewHolder=ViewHolder.getViewHolder(mContext,position,convertView,parent,R.layout.item_view);这段代码我也不想去写,怎么办呢?很简单getView方法不去抽象化,而引出一个抽象的方法,具体可以改成以下方式:


@Override
public View getView(int positionView convertViewViewGroup parent) {
    ViewHolder viewHoder = ViewHolder.getViewHolder(contextpositionconvertViewparentlayoutId);
    
convert(viewHoldermDatas.get(position));
    return 
viewHolder.getmConvertView();
}

protected abstract void convert(ViewHolder viewHolderObject item);


以后我们所有的Adapter继承这个万能的Adapter之后,只需要重写convert这个方法就好了,Object item是一个Bean,获取时要进行强转。


public class MyAdapter extends CourAdapter {
    public MyAdapter(List<Bean> dataContext context, int layoutId) {
        super(contextdatalayoutId);
    
}
    @Override
    
protected void convert(ViewHoder viewHoderObject item) {
        ((TextView)viewHolder.getView(R.id.tv_title)).
                setText(((Bean)item).getTitle());
        
((TextView)viewHolder.getView(R.id.tv_content)).
                setText(((Bean)item).getContent());
    
}

}


看看以上的代码,是不是就简单了很多呢。


3、控件直接赋值,让Adapter再次优化


经过以上的优化之后,代码大大的减少了,但是,我还想进行对其优化,也就是说,我连setText都不想去那么麻烦,这样的话,我们就是可以在ViewHolder这个类中去写控件赋值方法:


//TextView设置数据
public ViewHolder setText(int viewIdString txt) {
    TextView mTextView = getView(viewId);
    
mTextView.setText(txt);
    return this;
}


再看convert方法,是不是又一下简单的很多。


@Override
protected void convert(ViewHolder viewHolderObject item) {
    viewHolder.setText(R.id.tv_title,((Bean)item).getTitle())
            .setText(R.id.tv_content,((Bean)item).getContent());
}


当然了对于其它控件你也可以这样去做,比如ImageView:


public ViewHolder setPic(int viewIdString url) {
    ImageView mImageView = getView(viewId);
    
//ImageLoader.getInstance().loadImage(url,mImageView);
    
return this;
}



好了同志们,以上就是今天分享的所有内容,更多Android文章还请关注左侧栏中我的微信公众号,好累啊,拜拜了。


  • 6
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员一鸣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值