FrameAnimation 防止OOM

前言

作者在项目中遇到了一个有三百多帧的动画,第一想法就是:糟了,Android帧动画肯定用不了了,肯定会OOM,自己也是不死心,用了一下试试果然OOM了QAQ,那就另想办法吧。

于是就去Google,搜到了这么一篇文章:Android帧动画实现,防OOM,比原生动画集节约超过十倍的资源

然后就自己实现了一下:

    private fun play(currentFrame: Int) {
        runnable.currentFrame = currentFrame
        mImageView.postDelayed(runnable, mDuration)
    }

    inner class FrameRunnable : Runnable {
        var currentFrame = 0
        override fun run() {
            if (mPause) {
                mCurrentFrame = currentFrame
                return
            }
            mImageView.setBackgroundResource(mFrameRes[currentFrame])
            if (currentFrame == mLastFrame) {
                if (mIsRepeat) {
                    currentFrame = 0
                    mDuration = 50
                    play(0)
                }
            } else {
                currentFrame++
                play(currentFrame)
            }
        }

    }
复制代码

从代码中可以看出,通过不断地设置背景去实现序列帧动画,程序是不崩了,但是又有一个问题——内存抖动,可以看一下我的运行截图:

要想解决内存抖动,要知道什么是内存抖动,怎么定位内存抖动

内存抖动

简而言之,内存抖动是因为在短时间内大量的对象被创建又马上被释放。

有兴趣的同学可以看一下Google官方视频:Android Performance Patterns: Memory Churn and Performance

定位内存抖动

先看一下setBackgroundResource调用栈(PS:第一次画,哪里不对欢迎指正QAQ):

从上图基本可以看出来应该是 Bitmap被大量创建的原因,通过 Android Profiler也得到了证实。

解决内存抖动

通常我们遇到内存抖动的问题都会想到使用对象池,但是在这里怎样才能复用Bitmap呢,从上图可以看出这个过程好像没有办法干预,最后决定不使用setBackgroundResource而是使用setImageBitmap,这样不就可以从BitmapPool里取出Bitmap放进去了吗,可是问题又来了,由于播放的是序列帧每张图都不一样,如何做到复用Bitmap,所以这个方案个人认为无法实现。

后来,同事说BitmapFactory.Options有个inBitmap可以复用Bitmap,于是又去Google搜索用法, inBitmap主要就是指的复用内存块,不需要在重新给这个Bitmap申请一块新的内存,避免了一次内存的分配和回收,从而改善了运行效率。 有兴趣的同学可以看一下Google官方视频:Re-using Bitmaps

最终方案

class FrameAnimation {

    private val options: BitmapFactory.Options = BitmapFactory.Options()
    
    constructor() {
        ...
        //这个属性很关键,不加无法复用
        options.inMutable = true
        options.inBitmap = BitmapFactory.decodeResource(resources, resId, options)
    }
    
    inner class FrameRunnable : Runnable {
        
        override fun run() {
         
            val bitmap = BitmapFactory.decodeResource(resources, resId, options)
            mImageView.setImageBitmap(bitmap)
         
        }

    }
}
复制代码

最后看一下内存情况:

问题可算是解决了,哈哈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值