DanmakuFlameMaster缓存机制解析

1.         privateIDrawTask createDrawTask(boolean useDrwaingCache, DanmakuTimer timer, Contextcontext, int width, int height,                            booleanisHardwareAccelerated,                               IDrawTask.TaskListener taskListener)

useDrwaingCache为true,则创建CacheManagingDrawTask绘制任务

2.           构造方法中NativeBitmapFactory.loadLibs()加载了用于创建bitmapso文件,就是用skia图形处理库直接创建bitmap,缓存创建的是bitmap文件,如果直接调用drawTast()创建的是drawText()

3.           接着该调用CacheManagingDrawTask的prepare方法:

public void prepare() {

      assert (mParser != null);

      loadDanmakus(mParser);

      mCacheManager.begin();

}

4.           然后分两条主线去调用绘制缓存,一条是loadDanmakus()方法,另一个是mCacheManager.begin()方法。

5.           首先说是loadDanmakus()方法,首先从前面解析的parse中取出数据,保存在danmakuList中,parser设置完DanmakuContext,AndroidDisplayer,DanmakuTimer之后,再调用getDanmakus取出弹幕信息,解析方法中从JSONSource里解析每一条弹幕,包括弹幕的时间、颜色、类型、字号、用户id等内容。然后通过弹幕工厂DanmakuFactory创建弹幕,createDanmaku(int type, int viewportWidth, int viewportHeight, floatviewportScale, float scrollSpeedFactor),该方法为弹幕工厂中创建弹幕的方法,其中的功能包括修正弹幕宽高、缩放比、弹幕时长,滚动弹幕的时间设置,固定弹幕的时间设置。修正弹幕最长时长等功能。至此loadDanmakus()方法执行完毕。

6.           接着是第二个方法mCacheManager.begin()方法的执行流程,

两个函数mThread = new HandlerThread("DFM Cache-Building Thread")和mHandler =new CacheHandler(mThread.getLooper());其中创建了一个HandlerThread,然后创建了一个CacheHandler,所以CacheHandler发送消息后,处理消息内容都是在子线程。然后调用sendEmptyMessage(PREPARE)方法,调用CacheManager中CacheHandler的回调方法handleMessage()。

第一个casePREPARE中,     函数evictAllNotInScreen()负责清除所有不在屏幕内的缓存

for (inti = 0; i < 300; i++) {

  mCachePool.release(new DrawingCache());

}//在池里放300个预留缓存,以链式存储方式存放,在前面的代码会创建一个缓存个数上限为800的FinitePool池

第二个case DISPATCH_ACTIONS, 函数sendEmptyMessageDelayed(DISPATCH_ACTIONS,delayed),//会每隔半条弹幕时间发送一次DISPATCH_ACTIONS消息

其中具体的逻辑包括:如果上一次buildCache完成后得到的缓存弹幕末尾项的时间(上面分析过,这个值存在mCacheTimer.currMillisecond中)和主定时器当前时间之间的时间差值已经大于一条弹幕时间, 则会清除所有不在屏幕内的缓存,然后重新buildCache建立缓存;

如果缓存弹幕的第一项出现时间大于当前时间超过半屏,并且总缓存大小在规定最大值一半以下, 就要重新建立缓存;

如果总缓存大小在规定最大值一半以上,并且上一次建立缓存距离现在已经超过两条弹幕时间了,就要清除超时缓存;

如果总缓存大小快达到规定最大值,就等待下一次清除超时缓存;

缓存的第一条弹幕已经过时了,并且缓存弹幕末尾时间和现在时间差值已经超过一条弹幕时间了,先清除过时缓存,再重组缓存;

如果缓存的最后一条弹幕时间距离现在还有双倍弹幕时间多,则啥都不做;

剩余情况就是重组缓存。

第三个caseBUILD_CACHE,其中的逻辑包括:

1>先测量弹幕的宽高

2>在mCaches缓存的20条内查找和目标弹幕样式完全一样的弹幕(文字、大小、边框、下划线、颜色完全相同)

3>如果上述的查找样式完全相同的弹幕没有找到,则在前50条缓存中查找对比当前时间已经过时的,没有被重复引用的(只有上面那种情况才会增加引用计数,其他情况都不会),而且宽高和目标弹幕差值在规定范围内的弹幕,再根据目标弹幕样式,重新设置缓存(为每条弹幕创建一个bitmap和canvas,然后画出边框、下划线、文字等等)

4>如果上述两次查找缓存都没找到,则从FinitePool中取出一个,没有就new一个,然后同上配置DrawingCache

HandleMessage中处理消息的流程主要是以上三个,总结:子线程从发送PREPARE消息开始,然后接着发送了DISPATCH_ACTIONS消息;DISPATCH_ACTIONS消息处理逻辑内部又会发送DISPATCH_ACTIONS消息,时间间隔为半条弹幕时间就这样不断循环发送;DISPATCH_ACTIONS消息处理会调用dispatchAction方法,dispatchAction方法会发送BUILD_CACHES消息;BUILD_CACHES消息处理会调用prepareCaches方法,prepareCaches方法内部会调用buildCache方法为从当前时间开始的3倍弹幕时间内所有的弹幕做缓存

第四个case UPDATE:,其中的逻辑包括:updateInNewThread();该方法用于更新主定时器时间,然后执行postInvalidate,通知DanmakuView重绘,然后再发UPDATE消息,重复上述过程。

DanmakuView绘制过程分析:

如果弹幕还没有到出现时间,则检查它有没有缓存,如果没有则为它建立缓存;

measure 测量,在之前prepareCache已经为他们在buildCache时测量过了;

layout 布局,计算弹幕在屏幕上应该显示的位置;

draw 绘制弹幕。

  总结,其中还有一些缓存的清除略,缓存池的更新策略,弹幕位置的计算方法,弹幕的碰撞检测方法等,在缓存机制中都用到了

 

参考文献:

http://windrunnerlihuan.com/2016/07/02/DanmakuFlameMaster%E7%AE%80%E5%8D%95%E5%88%86%E6%9E%90/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值