ListView异步加载图片实现思路(优化篇)

ListView异步加载图片是常见的Android开发需求之一。在加载大量图片时,如果不使用异步加载,会严重影响应用性能和用户体验。本篇文章主要讲解如何使用ListView实现异步加载图片,并对其进行优化。

实现思路

  1. 创建一个ViewHolder类并在其中声明ImageView控件。
  2. 在ListView中加入标记每一个ImageView的Tag。
  3. 利用LruCache存储图片,防止因重复下载浪费流量和内存。
  4. 利用异步线程方法如AsyncTask或者线程池加载图片。
  5. 在视图重绘时检查标记,阻止重复加载,加快加载速度。

代码示例

下面给出使用异步加载图片优化ListView的代码示例。

步骤一:创建ViewHolder类

public class ViewHolder {
    public ImageView imageView;
}

步骤二:设置ImageView的Tag

if (convertView == null) {
    viewHolder = new ViewHolder();
    convertView = inflater.inflate(R.layout.list_item, parent, false);
    viewHolder.imageView = (ImageView) convertView.findViewById(R.id.ivImage);
    convertView.setTag(viewHolder);
} else {
    viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.imageView.setTag(position);

步骤三:使用LruCache存储图片

private LruCache<Integer, Bitmap> mMemoryCache;

private void init_lru() {
    //获取最大可用内存
    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

    //使用最大可用内存值的1/4作为缓存容量
    final int cacheSize = maxMemory / 4;

    mMemoryCache = new LruCache<Integer, Bitmap>(cacheSize) {
        @Override
        protected int sizeOf(Integer key, Bitmap bitmap) {
            // 重写此方法来衡量每张图片的大小,默认返回图片数量。
            return bitmap.getByteCount() / 1024;
        }
    };
}

public void addBitmapToMemoryCache(int key, Bitmap bitmap) {
    if (getBitmapFromMemoryCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }
}

public Bitmap getBitmapFromMemoryCache(int key) {
    return mMemoryCache.get(key);
}

步骤四:使用异步方式加载图片

private void loadImageAsyncTask(int position, ImageView imageView) {
    // 加载前先尝试从缓存中寻找
    final Bitmap bitmap = getBitmapFromMemoryCache(position);
    if (bitmap != null) {
        imageView.setImageBitmap(bitmap);
        return;
    }
    imageView.setImageResource(R.drawable.placeholder); // 显示占位图
    new AsyncTask<Integer, Void, Bitmap>() {
        private int mPosition;

        @Override
        protected Bitmap doInBackground(Integer... params) {
            mPosition = params[0];
            return decodeSampledBitmapFromResource(mResources, mImageIds[mPosition], mReqWidth, mReqHeight);
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            addBitmapToMemoryCache(mPosition, bitmap);
            ImageView imageView = (ImageView) mListView.findViewWithTag(mPosition);
            if (imageView != null && bitmap != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }.execute(position);
}

步骤五:阻止重复加载

在适配器getView()方法中,加上对ImageView的重复判断:

if (imageView.getTag() != null && imageView.getTag().equals(position)) {
    loadImageAsyncTask(position, viewHolder.imageView);
}

在计算图片样式的时候加上:

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // 源图片的高度和宽度
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        // 计算出实际宽高和目标宽高的比率
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);
        // 取比率中的最小值作为inSampleSize的值,这样可以保证最终图片的大小一定会大于这个目标大小或者与其相等。
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
    return inSampleSize;
}

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {

    BitmapFactory.Options options = new BitmapFactory.Options();
    // 当inJustDecodeBounds设置为true时,不会加载图片只会获取图片宽高信息。
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // 计算inSampleSize的值
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // 将inJustDecodeBounds设置为false,真正开始加载图片。
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

总结

使用上述代码族可以实现网速较慢的情况下,ListView中图片的延迟加载和优化。如果想要更高的性能优化,可以考虑使用RecyclerView等其他优化方法进一步优化。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:ListView异步加载图片实现思路(优化篇) - Python技术站

(0)
上一篇 2023年6月6日
下一篇 2023年6月6日

相关文章

  • asp.net(c#)动态修改webservice的地址和端口(动态修改配置文件)

    动态修改webservice的地址和端口可以通过修改web.config配置文件中的节点来实现,以下是详细攻略: 读取web.config配置文件 首先,我们需要读取web.config配置文件中的节点,可以使用ConfigurationManager类来实现。代码示例如下: Configuration conf = ConfigurationManager…

    C# 2023年6月3日
    00
  • China.com网站开发规范

    China.com网站开发规范 1. 前言 为了保证China.com网站的稳定性、可维护性和可扩展性,我们需要遵守一套标准的网站开发规范。本文档旨在为China.com网站的开发人员提供一些基本的规范和标准,帮助他们更好地编写规范化的代码并降低维护成本。 2. 代码规范 2.1. HTML规范 使用小写字母标签和属性,避免使用未定义的标签和属性 使用双引号…

    C# 2023年6月7日
    00
  • ASP.NET Mvc开发之EF延迟加载

    ASP.NET Mvc是一个广泛应用于Web应用程序开发的框架,其通过使用模型-视图-控制器(MVC)设计模式来促进代码的组织、维护和测试。而在ASP.NET Mvc应用程序的开发中,数据库访问和数据操作是非常重要的一部分,其中基于Entity Framework(EF)的数据操作是最常用的方式之一。 本攻略将详细讲解在ASP.NET Mvc开发中使用EF延…

    C# 2023年5月31日
    00
  • ASP.NET Core MVC中的标签助手(TagHelper)用法

    接下来我会给出关于“ASP.NET Core MVC中的标签助手(TagHelper)用法”的详细讲解。 什么是标签助手? 标签助手(TagHelper)是AspNet Core MVC 框架中一项非常有用的功能,它可以让我们简化开发工作。它能够提高视图页面的代码可读性和重用性,并且可以减少我们的代码量。它主要通过HTML标签来处理视图中的数据。在视图中,标…

    C# 2023年6月3日
    00
  • ASP.NET Core中的Controller使用示例

    ASP.NET Core是一个跨平台的开源Web框架,它可以用于构建高性能、可扩展的Web应用程序。在ASP.NET Core中,Controller是一个非常重要的组件,它用于处理HTTP请求并返回响应。在本文中,我们将详细讲解ASP.NET Core中的Controller使用示例。 创建一个Controller 在ASP.NET Core中,我们可以使…

    C# 2023年5月16日
    00
  • .NET发送邮件的实现方法示例

    下面是“.NET发送邮件的实现方法示例”的完整攻略: 前言 在现代应用程序开发中,发送邮件是一项非常重要的任务。而在.NET框架中,发送邮件是非常简单的。本篇文章将介绍如何使用.NET框架发送邮件。 1. 创建SMTP客户端 .NET框架有一个SMTPClient类,可以用来与SMTP服务器通信。以下代码演示了如何创建一个SMTP客户端: SmtpClien…

    C# 2023年5月31日
    00
  • 微软框架.NET Framework是什么附net framework下载地址

    “微软框架.NET Framework”是用于微软Windows操作系统上的一个开发框架,它可以用来创建和运行各种类型的应用程序,包括Web应用程序、桌面应用程序、移动应用程序和游戏等。 .NET Framework的作用 .NET Framework可以提供以下几方面的支持: 执行和管理应用程序的内存,包括对象生命周期、垃圾收集和线程管理; 提供一组预定义…

    C# 2023年5月31日
    00
  • C# 变量,常量数据类型详情

    下面我将为您详细讲解“C# 变量、常量、数据类型”的完整攻略。 变量 变量的定义 在C#中,变量是在使用前需要定义的。定义变量需要指定变量的名称、类型和初始值(可选)。变量的定义格式如下: data_type variable_name = initial_value; 其中,data_type为数据类型,variable_name为变量名称,initial…

    C# 2023年6月1日
    00
合作推广
合作推广
分享本页
返回顶部