##写在前面

很长时间没有更新博客了,因为最近一直在写即时聊天的Demo。跟着教程完成了一个基于XMPP的IM,完成后又写了一个基于环信的IM。感觉真心学了很多东西,都想分享出来,依次来吧。首先想说的就是关于ListView的一些知识。

ListView是Android中最常见也最难用的控件,因为ListView用处很多,几乎所有的APP都会用到这样一个控件。它基本的用法大家都知道,这里我就不再赘述了。本文主要是ListView的一些扩展知识,有以下几个方面:

  • 更改自带ListView主题的样式
  • 多样式ListView
  • ViewHolder的两种写法
  • ListView的效率优化
  • 一些干货网站推荐

##更改自带ListView主题的样式

我们知道,在大部分APP开发环境中,ListView都是需要自定义的。这里说的自定义意思是需要我们自定义一个适配器继承基本的Adapter类,比如BaseAdapter等。因为基本的Adapter不满足一些复杂的列表效果展示。当我们自定义Adapter的时候,就可以复写父类的方法,从而实现复杂的列表。比如这样:

而小部分场景呢,我们只需要基本的Adapter就可以了,比如只需要展示字符串,这个时候只需要绑定ArrayAdapter就能满足需求。

下面就是上面这个ListView的具体代码,很简单,不再解释。

/*** @ClassName: MainActivity* @Description:ListView的拓展* @author: iamxiarui@foxmail.com* @date: 2016年5月30日 下午2:15:46*/
public class MainActivity extends Activity {private ListView mainListView;private ArrayList<String> listData;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();initData();initAdapter();}/*** @Title: initView* @Description:初始化View* @return: void*/private void initView() {mainListView = (ListView) findViewById(R.id.lv_main);}/*** @Title: initData* @Description:初始化列表数据* @return: void*/private void initData() {listData = new ArrayList<String>();for (int i = 0; i < 30; i++) {listData.add("这是第 " + i + " 条数据");}}/*** @Title: initAdapter* @Description:绑定适配器* @return: void*/private void initAdapter() {mainListView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listData));}}
复制代码

可以看出,这里ListView的样式是android自带的样式android.R.layout.simple-list-item-1。当然说的重点不是这个,现在我们设想有这样一个需求。我们只需要展示字符串,没有复杂的样式,不需要自定义Adapter,但是我们需要在android自带样式的基础上,将列表中文字的颜色改成其他颜色或者更换文字大小。那该怎么做呢?

没错!就是复写**getView()**方法。代码如下:

/*** @Title: initAdapter* @Description:绑定适配器,并更改自带主题样式* @return: void*/
private void initAdapter() {mainListView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listData) {@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// 这里我们知道,item中只有一个TextView,可以直接写TextView textView = (TextView) super.getView(position, convertView, parent);textView.setTextColor(Color.BLUE);textView.setTextSize(36);return textView;}});
}
复制代码

现在运行后可以看出,样式已经发生了改变。

所以在没有自定义Adapter的前提下,我们仍然能对基本的Adapter做一些样式上的更改。

##多样式ListView

多样式ListView也是比较常见的,意思就是一个ListView中的item有多种样式。最常见的莫过于聊天记录的ListView了,发送者与接收者的消息是不同的样式。

那这样是如何做的呢?毫无疑问,我们需要自定义Adapter,但是在这里,我们复写的方法除了常用的**getCount()、getItem()、getItemId()、getView()**四个方法外,我们还需要复写下面两个方法:

  • public int getViewTypeCount() :这个方法是指定ListView中样式的数目,默认返回1
  • public int getItemViewType(int position) :根据参数positon指定当前item的样式类型

现在我们试着写出如下效果的ListView,条目依次不同,相当于一个ListView中存在两种样式。

代码中的重点就是下面的自定义Adapter,重点中的重点就是上面说到的两个方法的复写,具体如下:

/*** @ClassName: MyListAdapter* @Description:自定义两种样式的适配器* @author: iamxiarui@foxmail.com* @date: 2016年5月30日 下午2:51:00*/
public class MyListAdapter extends BaseAdapter {private Context context;private ArrayList<String> list;public MyListAdapter(Context context, ArrayList<String> list) {this.context = context;this.list = list;}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int position) {return list.get(position);}@Overridepublic long getItemId(int position) {return position;}/*** @Title: getViewTypeCount* @Description:两种样式* @return: 样式的数目*/@Overridepublic int getViewTypeCount() {return 2;}/*** @Title: getItemViewType* @Description:每个item的样式* @param position:item位置* @return: 样式*/@Overridepublic int getItemViewType(int position) {// 为了方便起见,我们根据奇偶项来区别样式,注意从0开始数if (position % 2 != 0) {// 奇数项返回0return 0;} else {// 偶数项返回0return 1;}}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {View view;if (convertView == null) {convertView = View.inflate(context, R.layout.item_list, null);}view = convertView;// 如果是奇数项if (getItemViewType(position) == 0) {TextView itemText = (TextView) view.findViewById(R.id.tv_item);itemText.setText(list.get(position));itemText.setTextColor(Color.BLUE);}// 如果是偶数项else if (getItemViewType(position) == 1) {TextView itemText = (TextView) view.findViewById(R.id.tv_item);itemText.setText(list.get(position));itemText.setTextColor(Color.GRAY);}return view;}}
复制代码

这样我们就完成了ListView中存在多样式的实现,有了这个简单例子,当然可以实现聊天记录列表或者其他更加复杂的多样式。

##ViewHolder的两种写法

ViewHolder是官方提出的一种优化ListView的工具,主要是减少了一些重复的操作,极大的提升了ListView的一些性能,当然这个大家也都非常熟悉了。

用我们之前的例子来看,它的一般写法是这样的:

/*** @ClassName: ViewHolder* @Description:定义ViewHolder类* @author: iamxiarui@foxmail.com* @date: 2016年5月30日 下午3:28:05*/
private static class ViewHolder {TextView itemText;
}@Override
public View getView(int position, View convertView, ViewGroup parent) {ViewHolder viewHolder;if (convertView == null) {// 不存在的时候,创建ViewHolderviewHolder = new ViewHolder();convertView = View.inflate(context, R.layout.item_list, null);viewHolder.itemText = (TextView) convertView.findViewById(R.id.tv_item);viewHolder.itemText.setText(list.get(position));// 存储ViewHolderconvertView.setTag(viewHolder);} else {// 存在的话直接复用viewHolder = (ViewHolder) convertView.getTag();}return convertView;
}
复制代码

效果图跟第一幅图一样,这里就不贴了。这种写法也是谷歌官方的写法,一般来说大家都这样写。

但是在看Github上一个开源库的时候,看到一个大神是这样写的:

/*** @ClassName: ViewHolder* @Description:定义ViewHolder类* @author: iamxiarui@foxmail.com* @date: 2016年5月30日 下午3:28:05*/
private static class ViewHolder {TextView itemText;// 构造函数中就初始化Viewpublic ViewHolder(View convertView) {itemText = (TextView) convertView.findViewById(R.id.tv_item);}// 得到一个ViewHolderpublic static ViewHolder getViewHolder(View convertView) {ViewHolder viewHolder = (ViewHolder) convertView.getTag();if (viewHolder == null) {viewHolder = new ViewHolder(convertView);convertView.setTag(viewHolder);}return viewHolder;}
}@Override
public View getView(int position, View convertView, ViewGroup parent) {ViewHolder viewHolder;if (convertView == null) {convertView = View.inflate(context, R.layout.item_list, null);}// 得到一个ViewHolderviewHolder = ViewHolder.getViewHolder(convertView);viewHolder.itemText.setText(list.get(position));return convertView;
}
复制代码

对比来看,在定义ViewHolder类的时候,需要实现构造函数,并封装得到ViewHolder的方法,看似是比原来的复杂很多,但是仔细推敲,这样做的好处有以下几点:

  • 将ViewHolder的实现方法完全封装在其本身的类中,功能更强大
  • 其方法与Adapter的getView()方法隔离,条理更加清晰
  • 当getView()中需要实现多种样式时,不需要写重复代码

所以在开发过程中,我一般选取第二种方式,虽然看似复杂很多,但是更加符合逻辑。

##ListView的效率优化

关于ListView的优化是很多开发者感到困扰的问题,比如ListView的卡顿、图片加载异常等问题十分棘手。其实提高ListView的流畅度只要记着两点就行了:

  • 复用View中的item
  • 异步处理耗时任务

这个问题在《Android开发艺术探索》中有专门的介绍,具体大概有四种方法:

###1、使用ViewHoler

不论是getView()方法中的convertView还是使用ViewHolder,其实基本原理都是复用已经用过的item。也就是在滑动过程中不需要一直new出新的View。而关于ViewHolder的具体使用,上面已经说过了,这里就不在赘述了。

###2、不在getView()中执行耗时任务

其实这个跟网络请求要在子线程中执行一样,不在UI线程中执行耗时任务,这样会造成主线程异常的卡顿。同样的在ListView中也不能在getView()方法中执行耗时任务,比如从网络上请求一些图片之类的。

关于加载图片我们可以使用ImageLoader实现,也就是异步的方式处理。

###3、控制异步任务的执行频率

其实这句话的意思就是,滑动的时候不执行异步加载,等停止滑动的时候再执行异步任务。这样就避免了滑动过程中的卡顿问题。

具体实现方式可以在**onScrollStateChange()**方法中定义一个滑动标志,然后在getView()中判断这个标志,如果已经停止滑动,那就启动加载任务。

###4、开启硬件加速

一般来说,复用View与异步加载方式已经能够解决ListView卡顿的情况,如果你还是不满意的话,可以尝试开启硬件加速,也可以解决一些卡顿问题。开启方式是在AndroidManifest.xml中对应的Activity添加下面这句:

android:hardwareAccelerated = "true"

项目源码

Github-IamXiaRui-Android_ListViewDemo

Github-IamXiaRui-RecyclerView


个人博客:www.iamxiarui.com 原文链接:http://www.iamxiarui.com/?p=674

Android:ListView的拓展与进阶相关推荐

  1. Android app应用开发高级进阶系列专栏解读

    1.前言 在从事android app开发的几年里,最开始接触做android 都是从app开发开始做的,在做app的这几年中把积累下来的做的一些功能,都整理出来了作为自己的技术资料,在以后开发类似的 ...

  2. android ListView包含Checkbox滑动时状态改变

    题外话: 在xamarin android的开发中基本上所有人都会遇到这个小小的坎,的确有点麻烦,当时我也折腾了好一半天,如果你能看到这篇博客,说明你和我当初也是一样的焦灼,如果你想解决掉这个小小的坎 ...

  3. Android ListView 自定义背景后 滚动时的背景变黑问题

    ListView是常用的显示控件,默认背景是和系统窗口一样的透明色,如果给ListView加上背景图片,或者背景颜色时,滚动时listView会黑掉,原因是,滚动时,列表里面的view重绘时,用的依旧 ...

  4. Android listview viewholder

    2019独角兽企业重金招聘Python工程师标准>>> Android ListView ViewHolder 利用adapter中的getView的 contentView 的复用 ...

  5. Android ListView常用用法

    ListView是比较常用的控件,但一直都觉得创建ListView步骤有点繁琐,故在此总结一下,方便查阅. 程序效果是实现一个ListView,ListView里面有标题,内容和图片,并加入点击和长按 ...

  6. 【腾讯Bugly干货分享】Android ListView与RecyclerView对比浅析--缓存机制

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5811d... 作者:黄宁源 一,背景 RecyclerView是谷歌官方出的一 ...

  7. Android ListView异步加载图片乱序问题,原因分析及解决方案

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/45586553 在Android所有系统自带的控件当中,ListView这个控件算是 ...

  8. Android ListView 圆角

    android ListView实现圆角实例教程二 Android框架浅析之锁屏(Keyguard)机制原理 http://www.eoeandroid.com/thread-181604-1-1.h ...

  9. Android listView 去掉header和footer中的分割线

    Android listView 去掉header和footer中的分割线 方法一: 在listView中加上android:headerDividersEnabled="false&quo ...

最新文章

  1. postmessage 消息接收延迟_微信为什么会突然延迟接收消息?原来是它们搞的鬼!...
  2. .Net Core扩展 SharpPlugs简单上手
  3. 像证券交易员一样思考_2.理解绝招
  4. NETCORE openSUSE docker 安装
  5. Java程序员如何在5年内从小白晋升为高手?
  6. Linux下Verilog仿真过程(二)
  7. android应用的界面编程----View与ViewGroup的概念
  8. Python SHA1加密算法
  9. 芯片内部长啥样?牛人用1500张照片,一层层放给你
  10. 介绍Jupyter和Pandas
  11. html项目_Python Selenium项目实战之添加发送HTML测试报告邮件!
  12. 除了云原生,2021 年还有这八大趋势值得关注
  13. 单元测试引入hsqldb探索
  14. 数字电路-时序逻辑电路
  15. SRTM 航天飞机雷达地形测绘使命
  16. python续行符是啥_python 续行符
  17. hotmail邮箱设置
  18. 控件中一些常用的属性和事件
  19. 5G NTN进展简述
  20. 酒吧类型与其娱乐项目设置

热门文章

  1. 【原创】ASP.NET C# 对SQL/ACCESS 数据库的备份和还原函数
  2. 关于在Mac上启动了模拟器/连接了手机之后。adb device一直提示List of devices attached的问题...
  3. nginx配置后重启无效与重启失败
  4. ios启动私有链查询区块信息
  5. 【CLR】解析AppDomain
  6. oracle goldengate实施简明介绍
  7. efs解密-Advanced EFS Data Recovery2.1-含注册KEY
  8. Linux内核第二节
  9. 第六课-Android四大组件之Activity
  10. 一杯“咸水”的人生哲理