使用Lottie动画导致内存暴增的原因之一

众所周知,Lottie是个非常赞的动画库,不过如果稍不注意,就会导致内存暴增,这里介绍其中一种情况。

最近公司有个需求是要在直播房间内播放一个礼物动画,用的是 Lottie,但是播放动画时,会卡个两秒,这种体验是十分不好的,另外播放期间内存会暴增至900+M,非常危险!必须得解决这个问题。

内存暴增

首先使用 Time Profiler 定位到卡顿的位置是在LayerImageProviderreloadImages()这个函数(这是用来加载动画的资源图片)

因为我们项目的礼物动画是会用到本地图片的,需要使用AnimationView(animation:, imageProvider:)方式创建动画,指定资源路径:

动画文件结构

reloadImages内部通过循环调用imageProvider.imageForAsset(asset:)来加载的,再点进去看看详细的代码:

原来 Lottie 是这么简单粗暴的加载图片(众所周知,UIImage(contentsOfFile:)方式创建的图片是不会缓存的,好处是使用完就能销毁,不过每次调用都是一个新的UIImage对象,不适合用在复用性高的图片),不过整个礼物动画也就20张小图片而已,怎么就暴增到900+M呢,在imageForAsset里面打印一下调用情况:

哇靠,好家伙,果然,即便同一张图片都重复创建了200+次,何况20张,一两秒内就加载了差不多4000多张,不卡才怪,难怪内存暴增900+M。

发现问题所在就好解决了,先将图片缓存起来,在动画播放期间内复用,不要重复创建即可。

好在 Lottie 可以让我们自定义imageProvider,做法很简单,初始化时先将 UIImage 缓存起来,再创建动画:

struct CacheImageProvider: AnimationImageProvider {
    let images: [String: CGImage]
    func imageForAsset(asset: ImageAsset) -> CGImage? {
        images[asset.name] ?? nil
    }
}
        
func startAnimation() {
    let anim = Animation.filepath(animJsonPath)

    var images: [String: CGImage] = [:]
    
    for fileName in fileNames {
        let imagePath = imageDirPath + "/\(fileName)" // 拼接完整路径
        guard let image = UIImage(contentsOfFile: imagePath) else { break }
        images[fileName] = cgImage
    }
    let provider = CacheImageProvider(images: images)
            
    let animView = AnimationView(animation: anim, imageProvider: subItem.provider)
    self.addSubview(animView)
    animView.play()
}

立马试试,不会再卡个两秒了,爽,再看看内存:

最高也就60M,并且动画结束就释放,舒服了~

另外,既然是提前缓存,可以参考YYWebImage的做法,再加个异步解码吧(系统默认是图片显示的那一刻才会解码,并且解码过程是在主线程),这样主线程就更加顺滑了:

struct CacheImageProvider: AnimationImageProvider {
    let images: [String: CGImage]
    func imageForAsset(asset: ImageAsset) -> CGImage? {
        images[asset.name] ?? nil
    }
}
        
func startAnimation() {
    DispatchQueue.global().async {
        let anim = Animation.filepath(animJsonPath)

        var images: [String: CGImage] = [:]
        
        for fileName in fileNames {
            let imagePath = imageDirPath + "/\(fileName)" // 拼接完整路径
            guard let image = UIImage(contentsOfFile: imagePath) else { break }
            guard let cgImage = image.jp.decode() else { break } // 解码
            images[fileName] = cgImage
        }
        let provider = CacheImageProvider(images: images)
                
        DispatchQueue.main.sync {
            let animView = AnimationView(animation: anim, imageProvider: subItem.provider)
            self.addSubview(animView)
            animView.play()
        }
    }
}

最终效果:

而且内存进一步减少至49M左右,毕竟使用CGBitmap方式绘制的图片直接适用于手机的显示,省去系统的自动解码过程:

到此为止最棘手的问题算是解决了~

最新更新

在新版的 Lottie 中,已经内置了CachedImageProvider,并且是默认使用的(顾名思义就是会对图片进行缓存的图片提供类,所以不会再像以前那样不断地创建、销毁UIImage对象了)。

  • PS:这是个私有类,它是在我们自定义的Provider上对其包装了一层来进行缓存。
扩展方法:将自定义的Provider包装成CachedImageProvider
在主要的构造方法中将Provider包装成CachedImageProvider来使用
替换Provider时包装成CachedImageProvider来使用

虽说现在已经有缓存了,不过并没有对其进行异步解码和压缩,这些操作还是需要我们自己去实现。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容