ListView性能

ListView的性能优化及进阶 1.ListView的介绍       ListView是Android中加载数据的重要控件,通俗的可以理解为,数据装载库。今天就来详细分析一番!可能有人会说,“大兄弟,RecyclerView都问世了,你还在纠结listview, 有意思么?”, 我呵呵不语.....我觉得任何被人称道过的人或物,都不会随着时间的流逝而过时,正因为有了listview的借鉴,RecyclerView才能破壳了, 阅读详情

ListView是一种可以显示一系列项目并能进行滚动显示的View。在每行里,既可以是简单的文本,也可以是复杂的结构。一般情况下,你都需要保证ListView运行得很好(即:渲染更快,滚动流畅)。在接下来的内容里,我将就ListView的使用,向大家提供几种解决不同性能问题的解决方案。

如果你想使用ListView,你就不得不使用ListAdapter来显示内容。SDK中,已经有了几种简单实现的Adapter:

·         ArrayAdapter<T> (显示数组对象,使用toString()来显示)

·         SimpleAdapter (显示Maps列表)

·         SimpleCursorAdapter(显示通过Cursor从DB中获取的信息)

这些实现对于显示简单的列表来说,非常棒!一旦你的列表比较复杂,你就不得不书写自己的ListAdapter实现。在多数情况下,直接从ArrayAdapter扩展就能很好地处理一组对象。此时,你需要处理的工作只是告诉系统如何处理列表中的对象。通过重写getView(int, View, ViewGroup)方法即可达到。

在这里,举一个你需要自定义ListAdapter的例子:显示一组图片,图片的旁边有文字挨着。

images with text in a ListView
ListView例:以图片文字方式显示的Youtube搜索结果

图片需要实时从internet上下载下来。让我们先创建一个Class来代表列表中的项目:

public class ImageAndText {

    private String imageUrl;

    private String text;

 

    public ImageAndText(String imageUrl, String text) {

        this.imageUrl = imageUrl;

        this.text = text;

    }

    public String getImageUrl() {

        return imageUrl;

    }

    public String getText() {

        return text;

    }

}

现在,我们要实现一个ListAdapter,来显示ImageAndText列表。

public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> {

 

    public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts) {

        super(activity, 0, imageAndTexts);

    }

 

    @Override

    public View getView(int position, View convertView, ViewGroup parent) {

        Activity activity = (Activity) getContext();

        LayoutInflater inflater = activity.getLayoutInflater();

 

        // Inflate the views from XML

        View rowView = inflater.inflate(R.layout.image_and_text_row, null);

        ImageAndText imageAndText = getItem(position);

 

        // Load the image and set it on the ImageView

        ImageView imageView = (ImageView) rowView.findViewById(R.id.image);

        imageView.setImageDrawable(loadImageFromUrl(imageAndText.getImageUrl()));

 

        // Set the text on the TextView

        TextView textView = (TextView) rowView.findViewById(R.id.text);

        textView.setText(imageAndText.getText());

 

        return rowView;

    }

 

    public static Drawable loadImageFromUrl(String url) {

        InputStream inputStream;

        try {

            inputStream = new URL(url).openStream();

        } catch (IOException e) {

            throw new RuntimeException(e);

        }

        return Drawable.createFromStream(inputStream, "src");

    }

}

这些View都是从“image_and_text_row.xml”XML文件中inflate的:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

              android:orientation="horizontal"

              android:layout_width="fill_parent"

              android:layout_height="wrap_content">

 

        <ImageView android:id="@+id/image"

                   android:layout_width="wrap_content"

                   android:layout_height="wrap_content"

                   android:src="@drawable/default_image"/>

 

        <TextView android:id="@+id/text"

                  android:layout_width="wrap_content"

                  android:layout_height="wrap_content"/>

 

</LinearLayout>

这个ListAdapter实现正如你所期望的那样,能在ListView中加载ImageAndText。但是,它唯一可用的场合是那些拥有很少项目、无需滚动即可看到全部的列表。如果ImageAndText列表内容很多的时候,你会看到,滚动起来不是那么的平滑(事实上,远远不是)。

性能改善

上面例子最大的瓶颈是图片需要从internet上下载。因为我们的代码都在UI线程中执行,所以,每当一张图片从网络上下载时,UI就会变得停滞。如果你用3G网络代替WiFi的话,性能情况会变得更糟。

为了避免这种情况,我们想让图片的下载处于单独的线程里,这样就不会过多地占用UI线程。为了达到这一目的,我们可能需要使用为这种情况特意设计的AsyncTask。实际情况中,你将注意到AsyncTask被限制在10个以内。这个数量是在Android SDK中硬编码的,所以我们无法改变。这对我们来说是一个制限事项,因为常常有超过10个图片同时在下载。

AsyncImageLoader

一个变通的做法是手动的为每个图片创建一个线程。另外,我们还应该使用Handler来将下载的图片invoke到UI线程。我们这样做的原因是我们只能在UI线程中修改UI。我创建了一个AsyncImageLoader类,利用线程和Handler来负责图片的下载。此外,它还缓存了图片,防止单个图片被下载多次。

public class AsyncImageLoader {

    private HashMap<String, SoftReference<Drawable>> imageCache;

 

    public AsyncImageLoader() {

        imageCache = new HashMap<String, SoftReference<Drawable>>();

    }

 

    public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {

        if (imageCache.containsKey(imageUrl)) {

            SoftReference<Drawable> softReference = imageCache.get(imageUrl);

            Drawable drawable = softReference.get();

            if (drawable != null) {

                return drawable;

            }

        }

        final Handler handler = new Handler() {

            @Override

            public void handleMessage(Message message) {

                imageCallback.imageLoaded((Drawable) message.obj, imageUrl);

            }

        };

        new Thread() {

            @Override

            public void run() {

                Drawable drawable = loadImageFromUrl(imageUrl);

                imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));

                Message message = handler.obtainMessage(0, drawable);

                handler.sendMessage(message);

            }

        }.start();

        return null;

    }

 

    public static Drawable loadImageFromUrl(String url) {

        // ...

    }

 

    public interface ImageCallback {

        public void imageLoaded(Drawable imageDrawable, String imageUrl);

    }

}

注意:我使用了SoftReference来缓存图片,允许GC在需要的时候可以对缓存中的图片进行清理。它这样工作:

·         调用loadDrawable(ImageUrl, imageCallback),传入一个匿名实现的ImageCallback接口

·         如果图片在缓存中不存在的话,图片将从单一的线程中下载并在下载结束时通过ImageCallback回调

·         如果图片确实存在于缓存中,就会马上返回,不会回调ImageCallback

在你的程序中,只能存在一个AsyncImageLoader实例,否则,缓存不能正常工作。在ImageAndTextListAdapter类中,我们可以这样替换:

ImageView imageView = (ImageView) rowView.findViewById(R.id.image);

imageView.setImageDrawable(loadImageFromUrl(imageAndText.getImageUrl()));

换成

final ImageView imageView = (ImageView) rowView.findViewById(R.id.image);

Drawable cachedImage = asyncImageLoader.loadDrawable(imageAndText.getImageUrl(), new ImageCallback() {

    public void imageLoaded(Drawable imageDrawable, String imageUrl) {

        imageView.setImageDrawable(imageDrawable);

    }

});

imageView.setImageDrawable(cachedImage);

使用这个方法,ListView执行得很好了,并且感觉滑动更平滑了,因为UI线程再也不会被图片加载所阻塞。

更好的性能改善

如果你尝试了上面的解决方案,你将注意到ListView也不是100%的平滑,仍然会有些东西阻滞着它的平滑性。这里,还有两个地方可以进行改善:

·         findViewById()的昂贵调用

·         每次都inflate XML

因此,修改代码如下:

public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> {

 

    private ListView listView;

    private AsyncImageLoader asyncImageLoader;

 

    public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {

        super(activity, 0, imageAndTexts);

        this.listView = listView;

        asyncImageLoader = new AsyncImageLoader();

    }

 

    @Override

    public View getView(int position, View convertView, ViewGroup parent) {

        Activity activity = (Activity) getContext();

 

        // Inflate the views from XML

        View rowView = convertView;

        ViewCache viewCache;

        if (rowView == null) {

            LayoutInflater inflater = activity.getLayoutInflater();

            rowView = inflater.inflate(R.layout.image_and_text_row, null);

            viewCache = new ViewCache(rowView);

            rowView.setTag(viewCache);

        } else {

            viewCache = (ViewCache) rowView.getTag();

        }

        ImageAndText imageAndText = getItem(position);

 

        // Load the image and set it on the ImageView

        String imageUrl = imageAndText.getImageUrl();

        ImageView imageView = viewCache.getImageView();

        imageView.setTag(imageUrl);

        Drawable cachedImage = asyncImageLoader.loadDrawable(imageUrl, new ImageCallback() {

            public void imageLoaded(Drawable imageDrawable, String imageUrl) {

                ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);

                if (imageViewByTag != null) {

                    imageViewByTag.setImageDrawable(imageDrawable);

                }

            }

        });

        imageView.setImageDrawable(cachedImage);

 

        // Set the text on the TextView

        TextView textView = viewCache.getTextView();

        textView.setText(imageAndText.getText());

 

        return rowView;

    }

}

这里有两点需要注意:第一点是drawable不再是加载完毕后直接设定到ImageView上。正确的ImageView是通过tag查找的,这是因为我们现在重用了View,并且图片有可能出现在错误的行上。我们需要拥有一个ListView的引用来通过tag查找ImageView。

另外一点是,实现中我们使用了一个叫ViewCache的对象。它这样定义:

public class ViewCache {

 

    private View baseView;

    private TextView textView;

    private ImageView imageView;

 

    public ViewCache(View baseView) {

        this.baseView = baseView;

    }

 

    public TextView getTextView() {

        if (textView == null) {

            textView = (TextView) baseView.findViewById(R.id.text);

        }

        return titleView;

    }

 

    public ImageView getImageView() {

        if (imageView == null) {

            imageView = (ImageView) baseView.findViewById(R.id.image);

        }

        return imageView;

    }

}

有了ViewCache对象,我们就不需要使用findViewById()来多次查询View对象了。

总结

我已经向大家演示了3种改进ListView性能的方法:

·         在单一线程里加载图片

·         重用列表中行

·         缓存行中的View

记录:MCGS和正弦变频器通讯 触摸屏实现对变频器:启动、停止、频率设定、频率读取、电压读取、电流读取。通讯方式Modbus RTU。 阅读详情

相关推荐

LightTools中VBA宏的编写入门

LightTools和VBA联动

bestgamer的博客 2348

ListView和DataGridView性能比较

最近在写一个程序涉及列表控件的大量数据刷新,使用了ListView控件,但觉得逐条向ListView添加数据的方式性能不是很高,想改为数据绑定方式,网上搜索半天发现ListView不支持数据绑定,作罢,索性测试下ListView和DataGridView的性能。   性能测试

3756

用Multisim仿真AD630锁定放大器:从2012年电赛A题实战到避坑指南

本文详细介绍了如何使用Multisim仿真AD630锁定放大器,从2012年电赛A题实战出发,提供完整的电路搭建、参数优化及避坑指南。重点解析AD630的开关调制架构和双相位检测的工程实现,帮助读者在强噪声背景下有效提取微弱信号,提升电子设计竞赛和工程实践中的信号处理能力。

weixin_42549451的博客 203

ListView性能[译]

原文路径:http://blog.jteam.nl/2009/09/17/exploring-the-world-of-android-part-2/ ListView是一种可以显示一系列项目并能进行滚动显示的View。在每行里,既可以是简单的文本,也可以是复杂的结构。一般情况下,你都需要保证ListView运行得很好(即:渲染更快,滚动流畅)。在接下来的内容里,我将就ListView...

de14141983的专栏 141

PX4无人机-Gazebo仿真实现动态目标追踪的视觉控制方案

本文详细介绍了PX4无人机在Gazebo仿真环境中实现动态目标追踪的视觉控制方案。从PX4与Gazebo仿真环境搭建、动态目标追踪核心技术栈、仿真环境深度定制技巧到追踪算法的优化实践,提供了全面的技术指导和常见问题排查方法,帮助开发者高效实现无人机视觉追踪功能。

weixin_29196315的博客 452

IFIX5.8在Win10系统下的安装避坑指南

本文提供了IFIX5.8在Windows 10系统下的详细安装教程与避坑指南。针对常见的驱动缺失、UAC拦截及兼容性报错等问题,文章从安装前准备、分步安装流程到安装后配置与驱动修复,给出了系统性的解决方案,帮助工控从业者顺利完成部署。

f6g7h8i9j的博客 364

RecyclerView 和 ListView 性能和效果区别

RecyclerView 和 ListView 布局效果的对比RecyclerView 和 ListView 一些常用的功能 和 API 的对比RecyclerView 和 ListView 在 Android L 引入嵌套滚动机制之后的对比 有一点需要强调下,文中所有的效果在真机上都是很流畅的,因为录制 GIF 图很容易掉帧,所以特地放慢了操作,千万不要误会成卡顿了啊! 布局效果对比

fanenqian的博客 1万+

W5500+STM32F103C8T6进行TCP通信(modbus)

一路生花一、w5500资料二、modbus通信三、从机代码四、总结五、参考 一、w5500资料 w5500的资料就放在下面了,单纯的客户端和其他模式上面有教程 https://www.aliyundrive.com/s/enPnnZgNtpE 二、modbus通信 Modbus RTU通信时使用的数据帧结构如下图,而Moubus TCP通信的数据帧和这个稍微不一样,没有crc检验,因为tcp本就是一种可靠传输协议 这里是Modbus TCP数据帧 公共功能码定义 三、从机代码

junseven164的博客 5780

listview加载性能优化ViewHolder

在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建。 ListView加载数据都是在public View getView(int position, View c

唐僧打怪兽 5万+

TT电机、310电机、370电机在智能小车与机器人中的性能对比与选型指南

本文深入对比了TT电机、310电机和370电机在智能小车与机器人项目中的核心性能差异。文章从尺寸、扭矩、转速、电压电流等关键参数入手,结合不同应用场景(如入门小车、竞技机器人、机械臂),提供了清晰的选型指南和驱动控制建议,帮助开发者根据项目需求选择最合适的电机方案。

weixin_29065015的博客 411

1. BES2700ZP概述

恒玄BES2700采用RTX5操作系统,配合mindmics算法或者自研算法。

雪飞_海 4476

ListView 用法大全、性能优化以及功能拓展

博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主威威喵原创,请多支持与指教。 本文首发于此 博主:威威喵|博客主页:https://blog.youkuaiyun.com/smile_running ListView,众所周知,这是一个android中元老级别的控件之一了。虽然,我们现在大多数都用RecyclerView来替代它,但是它还是在我们初学者...

你若盛开,蜜蜂自来 1万+

【从零开始学习SLAM】官方tf教程小海龟跟随程序

ros tf 进行坐标系之间转换的运算和发布

小秋 AI SLAM 入门实战教程 2034

idea和jdk安装与配置

idea和jdk安装之旅

Liu_wen_wen的博客 7376

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Mac电脑安装jdk,idea配置jdk

Mac电脑安装jdk,idea配置jdk

成钰的博客 1万+

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

IDEA配置JDK

IDEA配置jdk 一.前提条件:已经下载安装jdk,并且配置好环境变量。如没有安装,请点击下方链接,进行安装与配置。 链接在这里 二、配置jdk 1.打开IDEA,点开File->Project Structure,点击标签 2.点击SDK,如果没有,请点击NEW,然后点击JDK选择路径(地址是你自己的安装目录),然后点击OK,页面显示成功,结束配置。 ...

qq_41288473的博客 1万+

jdk8 下载 安装 配置及idea配置jdk环境

jdk8 下载 安装 配置及idea配置jdk环境

junR_980218的博客 1万+

idea需要安装jdk吗_idea安装需要配置jdk吗

需要配置sdk也就是jdk,也需要配tomcat。 环境要与项目相匹配idea自带jdk但是一般安装项目需要的jdk。 可以认为jdk只是sdk的一种(子集),因为它是开发java程序的一个平台,开发其他程序的sdk可以没有jdk.比如你下载了一个软件开发平台eclipse-SDK-3.2.2-win32.zip,它本...

计算机毕业论文源码,学生个人网页制作html源码。贴近用户做网络推广和互联网优化。 7066

IDEA如何配置Java环境,jdk路径

用IDEA开发java应用,首先需要安装好jdk,然后再在IDEA中配置安装好的jdk目录。我们在使用IDEA开发Java应用时,一般第一步就是需要配置好我们的jdk环境,并且在IDEA里面配置jdk的安装路径。如果有对Java入门开发相关的问题,可以关注我的公众号【Java入门学习】,我会持续更新Java相关的分享!然后,我们点击下【Project】,点击【Edit】,选择jdk的安装路径。这里,我们的JDK home path就是我们的jdk的安装目录根目录。最后,我们就配置好我们的jdk环境了。

会编程的蜗牛的博客 1861

Idea 配置JDK 版本 Idea 配置JDK1.8

Idea 配置JDK 版本 Idea 配置JDK 一、更改项目JDK 1、 File --- Project Structue --- Modules --- 设置JDK版本等 2、设定JDK编译版本: File --- Settings --- "compiler"

HaHa_Sir的博客 3万+

idea设置jdk路径_idea设置jdk版本

一.环境配置:1.1安装jdk,配置环境变量.1.2下载scala,并配置环境变量1.3安装playframe2框架:下载play并配置环境变量或者点击browseallversions选择更多版本,我安装的是play2.2.4.查看运行是否安装成功,控制台下运play二.下面。。 jdk好像不太正确.重新下载一个安装试...

计算机毕业论文源码,学生个人网页制作html源码。贴近用户做网络推广和互联网优化。 1707

IDEA如何配置jdk路径

首先要确定你的jdk已经安装好了 Win + R键,输入cmd 输入java -version 当返回这玩意的时候,就证明你的jdk已经安装成功,可以用IDEA进行配置了 打开IDEA的 File → Structure,快捷键Ctrl + Shift + Alt + S 选中SDKs,点击➕号,再点JDK 选中你的JDK安装目录 ...

weixin_30835923的博客 5583

idea配置jdk环境

一、新建项目前配置JDK 1.打开IDEA集成开发环境工具,点击:File–Project Structure,如下图 2.在打开的页面中,选择SDKs属性,并点击中间的加号+,选择JDK,如下图 3.在打开的页面中,选择本地计算机中已经安装的JDK目录(选择bin目录的上一级即可),然后点击OK,如下图 4.然后在Project Structure窗口,依次点击Apply–OK按钮即可,如下图 5.然后在工具中创建项目,下拉选择对应的JDK版本即可,如下图 ...

qq_48570211的博客 1万+

ListView使用及性能优化

一、ListView是Android中使用最广泛的一类控件,首先介绍其基本使用: 1、布局文件activity_main.xml中添加一个ListView组件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"

瀚海星空的博客 625

提高listview性能的几个方法

ListView优化一直是一个老生常谈的问题,不管是面试还是平常的开发中,ListView永远不会被忽略掉,那么这篇文章我们来看看如何最大化的优化ListView的性能。 在adapter中的getView方法中尽量少使用逻辑 尽最大可能避免GC 滑动的时候不加载图片 将ListView的scrollingCache和animateCache设置为false item的布局层级越烧越好 使用ViewHolder

不积跬步,无以至千里;不积小流,无以成江海。 1017

Android性能优化之提高ListView性能的技巧

ListView优化一直是一个老生常谈的问题,不管是面试还是平常的开发中,ListView永远不会被忽略掉,那么这篇文章我们来看看如何最大化的优化ListView的性能。

阿拉灯神灯的专栏 1万+

Android杂谈--内存泄露(1)--contentView缓存使用与ListView优化

引起Android内存泄露有很多种原因,下面罗列了一些问题,以后会一一解决 1、构造Adapter时没有使用缓存convertView(衍生出ListView优化问题) 2、查询数据库游标没有关闭 3、Activity中生命周期对象大于Activity生命周期(关于Application Context与Activity Context) 4、Bitmap对象不使用时没有recycle掉(...

weixin_34405354的博客 205
上一篇: Android中的Handler, Looper, MessageQueue和Thread
下一篇: java常用基础技术
gwpJava
博客等级 码龄14年 11粉丝 91原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值