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

简介: 传统的代码逻辑我们是怎么使用的呢?每写一个ListView,都要去写一个Adapter类,一个ViewHolder类,这几乎是我们必须要操作的,以致于有太多太多的冗余代码,让我们感到真的不厌其烦,一个两个还可以,十个八个,就真的有点太崩溃了,不仅代码繁琐,还会占用内存,为了解决这样的一个问题,下面就要开始对其抽取优化。

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


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

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

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


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


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


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


@OverridepublicViewgetView(intposition, ViewconvertView, ViewGroupparent) {
Viewview;
ViewHolderviewHolder;
if (convertView==null) {
view=View.inflate(mContext, R.layout.item_view, null);
viewHolder=newViewHolder();
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());
returnview;
}
privatestaticclassViewHolder {
TextViewtvTitle, tvContent;
}


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


publicstaticViewHoldergetViewHolder(Contextcontext, intposition,
ViewconvertView, ViewGroupparent, intlayoutId) {
if (convertView==null) {
returnnewViewHolder(context, position, parent, layoutId);
    } else {
ViewHolderviewHolder= (ViewHolder) convertView.getTag();
viewHolder.mPosition=position;
returnviewHolder;
    }
}


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


privateSparseArray<View>mView;
privateintmPosition;
privateViewmConvertView;
publicViewHolder(Contextcontext, intposition, ViewGroupparent, intlayoutId) {
mPosition=position;
mView=newSparseArray<View>();
mConvertView=View.inflate(context, layoutId, null);
mConvertView.setTag(this);
}


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


mPosition是记录索引位置。


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


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


public<TextendsView>TgetView(intlayoutId) {
Viewview=mView.get(layoutId);
if (view==null) {
view=getmConvertView().findViewById(layoutId);
mView.put(layoutId, view);
    }
return (T) view;
}


再写一个获取layout的方法:


publicViewgetmConvertView() {
returnmConvertView;
}


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


@OverridepublicViewgetView(intposition, ViewconvertView, ViewGroupparent) {
ViewHolderviewHolder=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());
returnviewHolder.getmConvertView();
}



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


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


publicabstractclassUniversalAdapter<T>extendsBaseAdapter {
protectedList<T>mDatas;
protectedContextcontext;
privateintlayoutId;
publicUniversalAdapter(Contextcontext, List<T>mDatas, intlayoutId) {
this.mDatas=mDatas;
this.context=context;
this.layoutId=layoutId;
    }
@OverridepublicintgetCount() {
returnmDatas.size();
    }
@OverridepublicObjectgetItem(intposition) {
returnmDatas.get(position);
    }
@OverridepubliclonggetItemId(intposition) {
returnposition;
    }
@OverridepublicabstractViewgetView(intposition, ViewconvertView, ViewGroupparent);
}


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


@OverridepublicViewgetView(intposition, ViewconvertView, ViewGroupparent) {
ViewHolderviewHoder=ViewHolder.getViewHolder(context, position, convertView, parent, layoutId);
convert(viewHolder, mDatas.get(position));
returnviewHolder.getmConvertView();
}
protectedabstractvoidconvert(ViewHolderviewHolder, Objectitem);


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


publicclassMyAdapterextendsCourAdapter {
publicMyAdapter(List<Bean>data, Contextcontext, intlayoutId) {
super(context, data, layoutId);
    }
@Overrideprotectedvoidconvert(ViewHoderviewHoder, Objectitem) {
        ((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设置数据publicViewHoldersetText(intviewId, Stringtxt) {
TextViewmTextView=getView(viewId);
mTextView.setText(txt);
returnthis;
}


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


@Overrideprotectedvoidconvert(ViewHolderviewHolder, Objectitem) {
viewHolder.setText(R.id.tv_title,((Bean)item).getTitle())
            .setText(R.id.tv_content,((Bean)item).getContent());
}


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


publicViewHoldersetPic(intviewId, Stringurl) {
ImageViewmImageView=getView(viewId);
//ImageLoader.getInstance().loadImage(url,mImageView);returnthis;
}


相关文章
|
11天前
|
存储 缓存 前端开发
安卓开发中的自定义控件实现及优化策略
【8月更文挑战第31天】在安卓应用的界面设计中,自定义控件是提升用户体验和实现特定功能的关键。本文将引导你理解自定义控件的核心概念,并逐步展示如何创建一个简单的自定义控件,同时分享一些性能优化的技巧。无论你是初学者还是有一定经验的开发者,这篇文章都会让你对自定义控件有更深的认识和应用。
|
4月前
|
存储 缓存 Android开发
构建高效的Android应用:采用RecyclerView优化列表显示
【4月更文挑战第2天】 在移动开发领域,列表显示是最常见的用户界面组件之一。对于Android平台而言,RecyclerView因其高效、灵活的特点而备受开发者青睐。本文将深入探讨如何利用RecyclerView在Android应用中实现流畅的列表滚动,以及通过各种优化策略来提升性能和用户体验。我们将从基本概念出发,逐步展开如何自定义适配器、视图持有者,以及利用布局管理器来实现复杂的列表布局。此外,还将讨论如何通过异步加载、缓存机制和动态数据更新来进一步优化性能。
67 1
|
Android开发
【安卓开发】借助setOnItemClickListener动态更新Listview
【安卓开发】借助setOnItemClickListener动态更新Listview
132 0
【安卓开发】借助setOnItemClickListener动态更新Listview
|
XML 缓存 IDE
Android修行手册-卡顿优化布局篇【建议收藏】
众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣!!!
227 0
|
缓存 Java Android开发
RecyclerView瀑布流优化方案探讨
目录介绍 01.规则瀑布流实现 02.不规则瀑布流实现 2.1 实现方式 2.2 遇到问题 03.瀑布流上拉加载 04.给瀑布流设置分割线 05.自定义Manager崩溃 06.如何避免刷新抖动 07.为何有时出现跳动 08.瀑布流图片优化 09.onBindViewHolder优化 10.瀑布流item点击事件优化 11.Glide加载优化 12.建议指定图片的宽高 欢迎同行探讨瀑布流极致优化方案 如果同行看到这篇文章,有好的瀑布流优化方案,欢迎给出建议,或者给链接也可以。
1930 0
|
Java Linux Android开发
深度 | Android 整体设计及背后意义
阿里妹导读:现实工作中经常可以听到这样的说法:框架的升级带来协议性能的提升、编程模式的变革带来业务的飞跃...... 姑且不论这些表述是否有问题,实际上如果系统地看待事物整体,可能会有不一样的发现。以LINUX为例,尽管其内核大获成功,但如果不是遵循POSIX、并成为一个开源、精简的UNIX实现,很难想象其最终会有何种发展。
|
编解码 Java Android开发
Andoid屏幕适配终极手段(小编用过最得劲的dp适配)
Andoid屏幕适配终极手段(小编用过最得劲的dp适配),1.工具类解析values目录下的dimens文件,根据其中所有的dimen标签,name和values,生成其他各种dp对应的dimens文件 2.
1282 0
|
Android开发
Android中最详细的焦点问题,从概念出发带你一点点分享(1)
版权声明:本文为sydMobile原创文章,转载请务必注明出处! https://blog.csdn.net/sydMobile/article/details/79530561 文章最早发布于我的微信公众号 Android_De_Home 中,欢迎大家扫描下面二维码关注微信公众获取更多知识内容。
1247 0