提高Android应用性能,LRUCache是个好帮手

在Android应用开发中,优化应用性能是一项非常重要的任务。应用程序的性能优化需要仔细考虑内存使用和缓存管理。在这篇文章中,我将介绍一种优化缓存管理的技术——LRUCache,并提供一些使用它的实际代码示例。

一、什么是LRUCache

LRUCache是一个Android内置的缓存管理类,它可以帮助我们高效地管理内存中的缓存对象。”LRU”代表最近最少使用(Least Recently Used)。该类按照值的最近使用次数自动回收缓存对象。当缓存空间满时,较早不使用的缓存对象将被回收,从而腾出空间。

二、使用LRUCache实现内存缓存

在实现内存缓存时,可以使用LRUCache类。接下来,我们将看到如何使用LRUCache执行内存缓存。

    private int cacheSize = 4 * 1024 * 1024; // 4 MiB
    private LRUCache memoryCache = new LRUCache(cacheSize) {
        protected int sizeOf(String key, Bitmap bitmap) {
            return bitmap.getByteCount();
        }
    };
    
    //向缓存中添加数据
    public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemCache(key) == null) {
            memoryCache.put(key, bitmap);
        }
    }
    
    //从缓存中获取数据    
    public Bitmap getBitmapFromMemCache(String key) {
        return memoryCache.get(key);
    }

在上面的代码中,我们使用LRUCache类表示一个内存缓存,它在存储数据时会自动回收内存。它使用Bitmap类作为缓存对象,并使用缓存对象的字节数来表示缓存的大小。

我们通过addBitmapToMemoryCache()方法向缓存中添加Bitmap对象,并通过getBitmapFromMemCache()方法从缓存中获取对象。以上代码段仅为参考,您需要根据实际情况自行实现相应的数据的添加和获取操作。

三、使用LRUCache实现磁盘缓存

实现磁盘缓存的方式与内存缓存有所不同。我们需要先将缓存对象写入磁盘,然后在需要时从磁盘中获取。请看下面的代码示例:

    private static final long DISK_CACHE_SIZE = 50 * 1024 * 1024; // 50 MiB
    private static final int DISK_CACHE_INDEX = 0;
    
    private DiskLruCache diskCache;

    //初始化磁盘缓存
    private void initDiskCache() {
        try {
            File cacheDir = getDiskCacheDir(mContext, "bitmap");
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
            diskCache = DiskLruCache.open(cacheDir, getAppVersion(), 1, DISK_CACHE_SIZE);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    //添加Bitmap对象到磁盘缓存中
    private boolean addBitmapToDiskCache(String key, Bitmap bitmap) {
        if (getBitmapFromDiskCache(key) == null) {
            try {
                DiskLruCache.Editor editor = diskCache.edit(key);
                if (editor != null) {
                    OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
                    editor.commit();
                    outputStream.close();
                    return true;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }
    
    //从磁盘缓存中获取Bitmap对象
    private Bitmap getBitmapFromDiskCache(String key) {
        try {
            DiskLruCache.Snapshot snapshot = diskCache.get(key);
            if (snapshot != null) {
                FileInputStream input = (FileInputStream) snapshot.getInputStream(DISK_CACHE_INDEX);
                return BitmapFactory.decodeStream(input);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    //获取磁盘缓存的路径
    private static File getDiskCacheDir(Context context, String uniqueName) {
        String cachePath = context.getCacheDir().getPath();
        return new File(cachePath + File.separator + uniqueName);
    }
    
    //获取应用程序当前版本号
    private int getAppVersion() {
        try {
            PackageInfo info = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);
            return info.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

在上面的代码段中,我们首先使用DiskLruCache类创建一个磁盘缓存。然后,我们使用addBitmapToDiskCache()方法将Bitmap对象写入磁盘缓存,使用getBitmapFromDiskCache()方法从缓存中获取Bitmap对象。

与内存缓存不同,磁盘缓存可存储所有类型的对象,而不仅仅是Bitmap。在使用时,我们需要自己负责缓存对象的序列化和反序列化。

四、LRUCache应用举例

接下来,我们将看到如何在实际的应用程序中应用LRUCache类。

假设我们需要在一个图片显示应用程序中使用LRUCache来管理图片缓存。该应用程序从一个网站中获取图片,并在屏幕上显示这些图片。为了优化应用程序的性能,我们需要使用LRUCache类来管理内存和磁盘缓存。

根据应用程序的需求,我们可以设计一个ImageLoader类来负责图片的加载和缓存。以下是该类的示例代码:

    public class ImageLoader {

        private final LRUCache memoryCache;
        private final DiskLruCache diskCache;

        public ImageLoader(Context context) {
            int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
            int cacheSize = maxMemory / 4;
            memoryCache = new LRUCache(cacheSize) {
                @Override
                protected int sizeOf(String key, Bitmap value) {
                    return value.getByteCount() / 1024;
                }
            };

            try {
                File cacheDir = getDiskCacheDir(context, "bitmap");
                if (!cacheDir.exists()) {
                    cacheDir.mkdirs();
                }
                diskCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, DISK_CACHE_SIZE);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //从内存缓存中获取图片
        public Bitmap getBitmapFromMemoryCache(String url) {
            return memoryCache.get(url);
        }

        //存储图片到内存缓存
        public void addBitmapToMemoryCache(String url, Bitmap bitmap) {
            if (getBitmapFromMemoryCache(url) == null) {
                memoryCache.put(url, bitmap);
            }
        }

        //从磁盘缓存中获取图片
        public Bitmap getBitmapFromDiskCache(String url) {
            Bitmap bitmap = null;
            String key = hashKeyForDisk(url);
            try {
                DiskLruCache.Snapshot snapshot = diskCache.get(key);
                if (snapshot != null) {
                    FileInputStream inputStream = (FileInputStream) snapshot.getInputStream(0);
                    FileDescriptor fileDescriptor = inputStream.getFD();
                    bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
                    if (bitmap != null) {
                        //存储图片到内存缓存
                        addBitmapToMemoryCache(url, bitmap);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return bitmap;
        }

        //下载图片并存储在本地磁盘缓存
        public void downloadBitmapToDiskCache(String url) {
            String key = hashKeyForDisk(url);
            try {
                DiskLruCache.Editor editor = diskCache.edit(key);
                if (editor != null) {
                    OutputStream outputStream = editor.newOutputStream(0);
                    if (downloadUrlToStream(url, outputStream)) {
                        editor.commit();
                    } else {
                        editor.abort();
                    }
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //将URL转换为磁盘缓存中的键
        private String hashKeyForDisk(String url) {
            String cacheKey;
            try {
                final MessageDigest mDigest = MessageDigest.getInstance("MD5");
                mDigest.update(url.getBytes());
                cacheKey = bytesToHexString(mDigest.digest());
            } catch (NoSuchAlgorithmException e) {
                cacheKey = String.valueOf(url.hashCode());
            }
            return cacheKey;
        }

        private String bytesToHexString(byte[] bytes) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < bytes.length; i++) {
                String hex = Integer.toHexString(0xFF & bytes[i]);
                if (hex.length() == 1) {
                    sb.append('0');
                }
                sb.append(hex);
            }
            return sb.toString();
        }

        private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
            HttpURLConnection urlConnection = null;
            BufferedOutputStream out = null;
            BufferedInputStream in = null;
            try {
                final URL url = new URL(urlString);
                urlConnection = (HttpURLConnection) url.openConnection();
                in = new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE);
                out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);

                int b;
                while ((b = in.read()) != -1) {
                    out.write(b);
                }
                return true;
            } catch (final IOException e) {
                e.printStackTrace();
            } finally {
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
                try {
                    if (out != null) {
                        out.close();
                    }
                    if (in != null) {
                        in.close();
                    }
                } catch (final IOException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }

        private static final int IO_BUFFER_SIZE = 8 * 1024;

        //获取应用程序当前版本号
        private int getAppVersion(Context context) {
            try {
                PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
                return info.versionCode;
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            return 1;
        }

        //获取磁盘缓存的路径
        private static File getDiskCacheDir(Context context, String uniqueName) {
            String cachePath = context.getCacheDir().getPath();
            return new File(cachePath + File.separator + uniqueName);
        }
    }    

ImageLoader类包含了所有必要的方法,包括从内存和磁盘缓存中获取图片、将图片添加到内存和磁盘缓存中、将URL转换为磁盘上的键等等。

在这个应用程序中,LRUCache使我们的缓存管理更容易实现。通过使用LRUCache,我们可以轻松地管理Android应用程序中的内存和磁盘缓存,从而最大限度地提高应用程序的性能。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/303706.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-31 11:50
下一篇 2024-12-31 11:50

相关推荐

  • 如何优化 Git 性能和重构

    本文将提供一些有用的提示和技巧来优化 Git 性能并重构代码。Git 是一个非常流行的版本控制系统,但是在处理大型代码仓库时可能会有一些性能问题。如果你正在处理这样的问题,本文将会…

    编程 2025-04-29
  • 使用@Transactional和分表优化数据交易系统的性能和可靠性

    本文将详细介绍如何使用@Transactional和分表技术来优化数据交易系统的性能和可靠性。 一、@Transactional的作用 @Transactional是Spring框…

    编程 2025-04-28
  • Android ViewPager和ScrollView滑动冲突问题

    Android开发中,ViewPager和ScrollView是两个常用的控件。但是当它们同时使用时,可能会发生滑动冲突的问题。本文将从多个方面介绍解决Android ViewPa…

    编程 2025-04-28
  • Android如何点击其他区域收起软键盘

    在Android应用中,当输入框获取焦点弹出软键盘后,我们希望能够点击其他区域使软键盘消失,以提升用户体验。本篇文章将说明如何实现这一功能。 一、获取焦点并显示软键盘 在Andro…

    编程 2025-04-28
  • Python性能优化方案

    本文将从多个方面介绍Python性能优化方案,并提供相应的示例代码。 一、使用Cython扩展 Cython是一个Python编译器,可以将Python代码转化为C代码,可显著提高…

    编程 2025-04-28
  • Python AUC:模型性能评估的重要指标

    Python AUC是一种用于评估建立机器学习模型性能的重要指标。通过计算ROC曲线下的面积,AUC可以很好地衡量模型对正负样本的区分能力,从而指导模型的调参和选择。 一、AUC的…

    编程 2025-04-28
  • Python性能分析: 如何快速提升Python应用程序性能

    Python是一个简洁高效的编程语言。在大多数情况下,Python的简洁和生产力为开发人员带来了很大便利。然而,针对应用程序的性能问题一直是Python开发人员需要面对的一个难题。…

    编程 2025-04-27
  • Android Studio HUD 实现指南

    本文将会以实例来详细阐述如何在 Android Studio 中使用 HUD 功能实现菊花等待指示器的效果。 一、引入依赖库 首先,我们需要在 build.gradle 文件中引入…

    编程 2025-04-27
  • Android和Vue3混合开发方案

    本文将介绍如何将Android和Vue3结合起来进行混合开发,以及其中的优势和注意事项。 一、环境搭建 在进行混合开发之前,需要搭建好相应的开发环境。首先需要安装 Android …

    编程 2025-04-27
  • Android Java Utils 可以如何提高你的开发效率

    Android Java Utils 是一款提供了一系列方便实用的工具类的 Java 库,可以帮助开发者更加高效地进行 Android 开发,提高开发效率。本文将从以下几个方面对 …

    编程 2025-04-27

发表回复

登录后才能评论