优化加载gif动画

文章转自:https://mp.weixin.qq.com/s?__biz=MzA3NjA3NTI5Mg==&mid=2656329608&idx=1&sn=9b26e25828112101bd898a521920f998&chksm=84c627fbb3b1aeedc76d711df000a230f8122f920e7eaac8e4ac2beca0502219f2b53e45c6b4&mpshare=1&scene=1&srcid=12228I8QamiflHBgDhZNZawR&key=564c3e9811aee0ab6916fb9ca3f862a9d762bed23faa15e4e7e2fdd0171e8633f0873a18f6ab77c8c3e3af80b24fd5bfa47d68db2011c843b6b4c03a175a0847f483a1899bef9845e6a586fc543673a9&ascene=0&uin=MTYzMjY2MTE1&devicetype=iMac+MacBookPro10%2C1+OSX+OSX+10.12.2+build(16C67)&version=12010210&nettype=WIFI&fontScale=100&pass_ticket=J%2BySkFufHrkUQmSQ9ma5sHID2qlp0Gk1afWsVSyCjZU%3D

项目开发中都会用到各种加载进度的动画,有几下几种方式可以参考:
1、使用animation-list一帧一帧的播放出来
最简单的方式是将设计同学给的png序列直接放到一个 animation-list中
优化加载gif动画_第1张图片
然后直接,放在设置为一个ImageView就可以了
优化加载gif动画_第2张图片
这个方法如果图片过多就会导致oom;
2、使用一个线程来读取PNG序列,另外一个线程去播放读取出来的PNG序列,那么有一些问题我们要去面对:
a、一个线程来读,一个线程写,读PNG的线程写,播PNG的线程读,哎呀,有点拗口~~,不过很显然,这是一个《生产者-消费者模型》,那么问题是使用什么存放读取好的bitmap呢,使用BlockingQueue 吧,为什么要使用BlockingQueue,如果不懂,请点击这里,还能不能使用别的,当然,有,而且还不止一个,感兴趣可以去这个包下java.util.concurrent探索下。

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。

b、不是怕OOM吗?那么,这个方案是否可以解决OOM呢?但是显然是肯定的了。为什么这么说,都到了这种粒度了,OOM当然是可以解决。

b1、首先,我们可以拿到当前的最大内存Runtime.getRuntime().maxMemory(),和当前的可用内存Runtime.getRuntime().freeMemory();
因此,结合BitmapFactory.Options,的这个inJustDecodeBounds属性,你完全可以判断是否还有足够的内存加载更多的bitmap。

b2、其次,维护一个currentSize,记录解析到内存测bitmap占用的内存,每读一张,currentSize+读出来的bitmap占用的内存,currentSize显然是变动的,播放完的bitmap请补上一刀,currentSize - 刚刚播放完的bitmap。
优化加载gif动画_第3张图片
3、多线程读取PNG
优化加载gif动画_第4张图片
当然,多线程并发去读取,怎样能够保证读取出来的某个PNG是不是应该在它正确的位置呢?
很显然要做到这一点,就需要将png的序号带入到读取线程中。读取线程读取完毕之后,去问一个manger,大哥,有比我小的读取线程还没有提交他拿到的bitmap吗?大哥告诉你还有,那对不起,你乖乖等一会吧,wait(关键字),对么?如果大哥告诉你没有,你丫就是序号最小的那个哦,那你就把bitmap交给BlockingQuene吧,然而自己就完成光荣使命了。

可问题是,如果你在wait,谁来叫醒你呢?大哥说,他来notify,大哥收到最小的序号的提交的bitmap,等等,(上面说错了,最小的需要把bitmap交给大哥来提交,),将bitmap交给BlockingQuene,然后大哥此时通知所有读取线程的小弟们,大伙赶紧来交作业了,如是此时你单身10年的左手终于抢到了“锁”,如是,你把你的作业bitmap交给了大哥了。

还有一种思路就是对号入座:这种情况表达0123已经提交给BlockingQuene,5先完成了,然后3完成了,4没完成,此时大哥会吧3提交给BlockingQuene对吗?显然是,情况还有很多,,可以自己脑补一下,总之,这么做,读取线程只要读取完毕,把作业交给大哥就好,不用等待大哥说你是最小的,才让你提交,是吗?
优化加载gif动画_第5张图片
okay,整体思路就是这样,看看效果吧,go。。。
优化加载gif动画_第6张图片
4、单线程读取,重复利用释放的bitmap资源
google给了我这么一个答案:
https://developer.android.com/training/displaying-bitmaps/manage-memory.html#recycle
这里写图片描述
options有这么一个参数 ,可以重用一个bitmap的内存去存放解析出另外一个新的bitmap,但是有一定的要求:
4.4以上,只需要old bitmap字节数比将要加载的bitmap所需的字节数大,但是低于4.4,要满足和待加载bitmap长宽像素一致即可 (更加苛刻)。

而我们的png序列,每张图片都是一样大小,显然,符合这个所有特性(长宽一致)。

如是,有多了集合去存储即将释放的bitmap,用来重用。
这里写图片描述
测试结果:
优化加载gif动画_第7张图片

你可能感兴趣的:(安卓开发)