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日

相关文章

  • 关于c#中单例模式的一些问题

    下面给您详细讲解关于C#中单例模式的一些问题。 什么是单例模式? 单例模式是一种常见的设计模式,其定义为:确保一个类只有一个实例,并提供一个全局访问点。这意味着在整个应用程序中,只会有一个该类的实例存在,而且该实例可以被任何部分访问并进行更改。 为什么要使用单例模式? 单例模式主要用于节省系统资源,因为在某些情况下,多个实例的存在会带来很大的性能影响,而只有…

    C# 2023年6月7日
    00
  • C#调用动态unlha32.dll解压Lha后缀的打包文件分享

    要讲解“C#调用动态unlha32.dll解压Lha后缀的打包文件分享”的完整攻略,我们需要掌握以下知识点: unlha32.dll是什么 如何在C#中调用unlha32.dll 如何解压Lha后缀的打包文件 接下来,我们将分别讲解每个知识点,并结合示例说明。 1. unlha32.dll是什么 unlha32.dll是一个解压缩工具,可以解压多种类型的压缩…

    C# 2023年6月8日
    00
  • ASP.NET页面进行GZIP压缩优化的几款压缩模块的使用简介及应用测试!(附源码)第1/2页

    ASP.NET页面进行GZIP压缩优化的几款压缩模块的使用简介及应用测试 简介 GZIP压缩是一种常用的网页页面优化技术。传输时,服务端对浏览器请求的数据进行压缩,减少传输数据量,提高页面的加载速度。本文将介绍ASP.NET页面进行GZIP压缩优化的几款压缩模块的使用方法,并进行应用测试。 使用方法 在ASP.NET网站中实现GZIP压缩,需要使用第三方的压…

    C# 2023年5月31日
    00
  • Windows 8 应用框架理解及开发工具使用实例教程

    Windows 8 应用框架理解及开发工具使用实例教程 理解Windows 8应用框架 Windows 8应用框架是一套用于开发Windows Store应用程序的技术框架,为开发人员提供了一些现代化的开发工具和API。当我们使用Windows 8开发应用时,我们需要使用一些特定于Windows 8的技术,例如Windows Runtime API、C#、J…

    C# 2023年6月7日
    00
  • C#实现XML文件与DataTable、Dataset互转

    下面我为您详细讲解C#实现XML文件与DataTable、Dataset互转的完整攻略。 转换DataTable为XML文件 在C#中将DataTable转换为XML文件非常简单,我们可以通过DataTable的WriteXml方法来实现转换。该方法用于把DataTable中的数据写入到XML文件中,并可在需要时指定XML文件的路径及名称。具体的示例代码如下…

    C# 2023年5月31日
    00
  • 如何使用C#程序给PDF文件添加编辑域

    下面是使用C#程序给PDF文件添加编辑域的完整攻略: 准备工作 在开始添加编辑域之前,我们需要准备一些工作。首先,我们需要下载和安装iTextSharp,这是一个开源的PDF编辑库。其次,我们需要安装Adobe Acrobat DC,这是一个非常流行的PDF编辑器,我们后续需要用它来验证PDF文件中添加的编辑域是否有效。 添加编辑域 一旦我们准备好了工作,我…

    C# 2023年6月1日
    00
  • C# Distinct和重写IEqualityComparer时要知道的二三事

    C# 中的 Distinct 方法用于从一个序列中筛选出不同的元素,这些元素是根据它们的默认相等性比较器进行比较的。然而,在一些情况下,我们希望通过自定义相等性比较器来进行元素比较。这时就需要重写 IEqualityComparer 接口,使用自定义的相等性比较器来进行元素比较。下面是关于 C# 中 Distinct 方法和自定义比较器的攻略: 1. 相关基…

    C# 2023年6月1日
    00
  • C#中ArrayList 类的使用详解

    C#中ArrayList 类的使用详解 在C#语言中,ArrayList类是一个非常重要的类,它允许我们在一个集合中存储对象数组。ArrayList类在.NET Framework中作为一个动态数组使用,这就意味着可以在运行时自由地增加或者减少数组的大小,而且类型也是可以变化的。下面我们来详细分析ArrayList类的使用方法。 初始化ArrayList类 …

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