美文网首页
Android处理位图时的问题及解决方案

Android处理位图时的问题及解决方案

作者: 安安_660c | 来源:发表于2022-11-13 11:33 被阅读0次

    在Android应用程序中加载位图是一项棘手的任务。位图占用大量内存。例如,在Pixel 6 Pro上拍摄的照片具有大约1250万像素(4080 x 3072)。使用ARGB_的位图配置(每像素4个字节),将照片加载到内存中需要大约50MB的内存。如此大的位图会很快耗尽应用程序的内存预算。

    幸运的是,有很多图书馆帮助我们解决这个问题。一些流行的图像加载库包括来自Square的毕加索、Instacart的Coil、Facebook的Fresco和Typeguard,Inc.的Glide。这些库简化了大部分与位图和Android上其他类型图像相关的复杂任务,例如获取、解码和显示位图。很高兴了解这些库如何有效地处理位图,使我们的生活更轻松。在本文中,我们将讨论处理位图时可能遇到的一些问题以及如何解决这些问题。

    位图的问题

    我们已经讨论过位图会占用大量的应用程序内存。这可能会导致几个问题:

    可能 发生内存不足错误
    UI或ANR响应速度慢
    图像的缓慢获取和显示
    让我们看看如何解决这些问题。

    内存不足

    图像有各种形状和大小。在大多数情况下,它们比显示它们所需的UI组件大。将4080 x 3072图像加载到内存中,然后仅在较小的1020 x 768视图上显示它是没有意义的。高分辨率的图像不会带来任何可见的好处,但仍会占用宝贵的内存。理想情况下,我们只想将图像的较小版本加载到内存中。我们怎么能做到呢?

    首先,我们需要找出图像有多大 位图工厂类提供一个名为InJustDecodeBounds,它可用于读取图像的尺寸和类型,而无需为该位图实际分配内存。

    val options = BitmapFactory.Options().apply {
        inJustDecodeBounds = true
    }
    BitmapFactory.decodeResource(resources, R.id.myimage, options)
    val imageHeight: Int = options.outHeight
    val imageWidth: Int = options.outWidth
    val imageType: String = options.outMimeType
    

    在找到图像维度之后,我们需要加载它的缩小版本,以匹配要加载图像的目标UI组件的尺寸。我们可以使用 无样品选项。请注意,解码器使用基于2的幂的最终值,任何其他值都将向下舍入到最接近的2的幂次。

    fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
        // Raw height and width of image
        val (height: Int, width: Int) = options.run { outHeight to outWidth }
        var inSampleSize = 1
    
        if (height > reqHeight || width > reqWidth) {
    
            val halfHeight: Int = height / 2
            val halfWidth: Int = width / 2
    
            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) {
                inSampleSize *= 2
            }
        }
    
        return inSampleSize
    }
    

    UI响应速度慢

    在UI线程上加载位图会降低应用程序的性能。因此,在后台线程上解码位图是很重要的。此外,我们应该在内存上建立一个缓存来快速访问解码后的位图。

    在Android中,生成位图缓存的推荐方法是使用LruCache,在过去,流行的内存缓存实现是SoftReference或 WeakReference公司位图缓存。然而,在后一个Android版本中,垃圾收集器在收集软/弱引用方面更为积极,这使得它们相当无效。做好LruCache,我们应该考虑一些因素,例如:

    其余活动和应用程序的内存密集程度如何,缓存中的每个位图将占用多少内存?
    质量与数量的权衡。存储大量低质量位图是否更好?
    一次屏幕上会显示多少图像?访问这些图像的频率是多少?
    回答这些问题将帮助我们确定缓存的合适大小。

    除此之外,位图很大,因此它使垃圾回收器(GC)更频繁地运行。在这里,您可以使用位图池来提高处理位图的效率。位图池将重用位图,避免在应用程序中连续分配和取消分配内存,减少GC开销。GC运行时间越短,应用程序完成任务的时间就越长。

    下载速度慢的图像

    通过网络发送数据可能需要很长时间,尤其是对于位图这样的大数据。磁盘缓存通常可以帮助组件快速重新加载下载的图像。当然,从磁盘获取图像比从内存加载要慢,但它仍然非常有用,因为内存缓存并不总是可用的。内存缓存可以用大型数据集快速填充,如果应用程序在后台太长时间,则会被销毁。

    在图像访问频率更高的应用程序中(如图像库应用程序),ContentProvider可能是存储缓存图像的更合适的位置。

    相关文章

      网友评论

          本文标题:Android处理位图时的问题及解决方案

          本文链接:https://www.haomeiwen.com/subject/qgdlxdtx.html