private void evictAllNotInScreen(boolean removeAllReferences) { if (mCaches != null) { IDanmakuIterator it = mCaches.iterator(); while (it.hasNext()) { BaseDanmaku danmaku = it.next(); IDrawingCache<?> cache = danmaku.cache; boolean hasReferences = cache != null && cache.hasReferences(); if (removeAllReferences && hasReferences) { if (cache.get() != null) { mRealSize -= cache.size(); cache.destroy(); } entryRemoved(true, danmaku, null); it.remove(); continue; } if (danmaku.hasDrawingCache() == false || danmaku.isOutside()) { entryRemoved(true, danmaku, null); it.remove(); } } // mCaches.clear(); } mRealSize = 0; }
@Override protected void onDanmakuRemoved(BaseDanmaku danmaku) { super.onDanmakuRemoved(danmaku); if (danmaku.hasDrawingCache()) { if (danmaku.cache.hasReferences()) { danmaku.cache.decreaseReference(); } else { danmaku.cache.destroy(); } danmaku.cache = null; } }
private final void addDanmakuAndBuildCache(BaseDanmaku danmaku) { if (danmaku.isTimeOut() || danmaku.time > mCacheTimer.currMillisecond + mContext.mDanmakuFactory.MAX_DANMAKU_DURATION) { return; } if (danmaku.priority == 0 && danmaku.isFiltered()) { return; } if (!danmaku.hasDrawingCache()) { buildCache(danmaku, true); } if (danmaku.isLive) { mCacheTimer.update( mTimer.currMillisecond + mContext.mDanmakuFactory.MAX_DANMAKU_DURATION * mScreenSize); } }
private BaseDanmaku findReuseableCache( BaseDanmaku refDanmaku, boolean strictMode, int maximumTimes) { IDanmakuIterator it = mCaches.iterator(); int slopPixel = 0; if (!strictMode) { slopPixel = mDisp.getSlopPixel() * 2; } int count = 0; while (it.hasNext() && count++ < maximumTimes) { // limit maximum times BaseDanmaku danmaku = it.next(); if (!danmaku.hasDrawingCache()) { continue; } if (danmaku.paintWidth == refDanmaku.paintWidth && danmaku.paintHeight == refDanmaku.paintHeight && danmaku.underlineColor == refDanmaku.underlineColor && danmaku.borderColor == refDanmaku.borderColor && danmaku.textColor == refDanmaku.textColor && danmaku.text.equals(refDanmaku.text)) { return danmaku; } if (strictMode) { continue; } if (!danmaku.isTimeOut()) { break; } if (danmaku.cache.hasReferences()) { continue; } float widthGap = danmaku.cache.width() - refDanmaku.paintWidth; float heightGap = danmaku.cache.height() - refDanmaku.paintHeight; if (widthGap >= 0 && widthGap <= slopPixel && heightGap >= 0 && heightGap <= slopPixel) { return danmaku; } } return null; }
private long prepareCaches(boolean repositioned) { long curr = mCacheTimer.currMillisecond; long end = curr + mContext.mDanmakuFactory.MAX_DANMAKU_DURATION * mScreenSize; if (end < mTimer.currMillisecond) { return 0; } long startTime = SystemClock.uptimeMillis(); IDanmakus danmakus = null; int tryCount = 0; boolean hasException = false; do { try { danmakus = danmakuList.subnew(curr, end); } catch (Exception e) { hasException = true; SystemClock.sleep(10); } } while (++tryCount < 3 && danmakus == null && hasException); if (danmakus == null) { mCacheTimer.update(end); return 0; } BaseDanmaku first = danmakus.first(); BaseDanmaku last = danmakus.last(); if (first == null || last == null) { mCacheTimer.update(end); return 0; } long deltaTime = first.time - mTimer.currMillisecond; long sleepTime = 30 + 10 * deltaTime / mContext.mDanmakuFactory.MAX_DANMAKU_DURATION; sleepTime = Math.min(100, sleepTime); if (repositioned) { sleepTime = 0; } IDanmakuIterator itr = danmakus.iterator(); BaseDanmaku item = null; long consumingTime = 0; int orderInScreen = 0; int currScreenIndex = 0; int sizeInScreen = danmakus.size(); // String message = ""; while (!mPause && !mCancelFlag) { boolean hasNext = itr.hasNext(); if (!hasNext) { // message = "break at not hasNext"; break; } item = itr.next(); if (last.time < mTimer.currMillisecond) { // message = "break at last.time < mTimer.currMillisecond"; break; } if (item.hasDrawingCache()) { continue; } if (repositioned == false && (item.isTimeOut() || !item.isOutside())) { continue; } if (!item.hasPassedFilter()) { mContext.mDanmakuFilters.filter( item, orderInScreen, sizeInScreen, null, true, mContext); } // Log.e("prepareCache", currScreenIndex+","+orderInScreen+"," + item.time+"skip:"+skip); if (item.priority == 0 && item.isFiltered()) { continue; } if (item.getType() == BaseDanmaku.TYPE_SCROLL_RL) { // 同屏弹幕密度只对滚动弹幕有效 int screenIndex = (int) ((item.time - curr) / mContext.mDanmakuFactory.MAX_DANMAKU_DURATION); if (currScreenIndex == screenIndex) orderInScreen++; else { orderInScreen = 0; currScreenIndex = screenIndex; } } if (!repositioned) { try { synchronized (mDrawingNotify) { mDrawingNotify.wait(sleepTime); } } catch (InterruptedException e) { e.printStackTrace(); break; } } // build cache if (buildCache(item, false) == RESULT_FAILED) { // message = "break at build failed"; break; } if (!repositioned) { consumingTime = SystemClock.uptimeMillis() - startTime; if (consumingTime >= DanmakuFactory.COMMON_DANMAKU_DURATION * mScreenSize) { // message = "break at consumingTime out:" + consumingTime; break; } } } consumingTime = SystemClock.uptimeMillis() - startTime; if (item != null) { mCacheTimer.update(item.time); // Log.i("cache","stop at :"+item.time+","+count+",size:"+danmakus.size()+","+message); } else { mCacheTimer.update(end); } return consumingTime; }
public void invalidateDanmaku(BaseDanmaku danmaku) { if (mHandler != null && danmaku.hasDrawingCache()) { mHandler.obtainMessage(CacheHandler.REBUILD_CACHE, danmaku).sendToTarget(); } }
@Override public void handleMessage(Message msg) { int what = msg.what; switch (what) { case PREPARE: evictAllNotInScreen(); for (int i = 0; i < 300; i++) { mCachePool.release(new DrawingCache()); } case DISPATCH_ACTIONS: // Log.e(TAG,"dispatch_actions:"+mCacheTimer.currMillisecond+":"+mTimer.currMillisecond); long delayed = dispatchAction(); if (delayed <= 0) { delayed = mContext.mDanmakuFactory.MAX_DANMAKU_DURATION / 2; } sendEmptyMessageDelayed(DISPATCH_ACTIONS, delayed); break; case BUILD_CACHES: removeMessages(BUILD_CACHES); boolean repositioned = ((mTaskListener != null && mReadyState == false) || mSeekedFlag); prepareCaches(repositioned); if (repositioned) mSeekedFlag = false; if (mTaskListener != null && mReadyState == false) { mTaskListener.ready(); mReadyState = true; } // // Log.i(TAG,"BUILD_CACHES:"+mCacheTimer.currMillisecond+":"+mTimer.currMillisecond); break; case ADD_DANMAKKU: BaseDanmaku item = (BaseDanmaku) msg.obj; addDanmakuAndBuildCache(item); break; case REBUILD_CACHE: Pair<BaseDanmaku, Boolean> pair = (Pair<BaseDanmaku, Boolean>) msg.obj; if (pair != null) { BaseDanmaku cacheitem = pair.first; if (pair.second) { cacheitem.requestFlags |= BaseDanmaku.FLAG_REQUEST_REMEASURE; } cacheitem.requestFlags |= BaseDanmaku.FLAG_REQUEST_INVALIDATE; if (!pair.second && cacheitem.hasDrawingCache() && !cacheitem.cache.hasReferences()) { DrawingCache cache = DanmakuUtils.buildDanmakuDrawingCache( cacheitem, mDisp, (DrawingCache) cacheitem.cache); cacheitem.cache = cache; push(cacheitem, 0, true); return; } if (cacheitem.isLive) { clearCache(cacheitem); createCache(cacheitem); } else { entryRemoved(true, cacheitem, null); addDanmakuAndBuildCache(cacheitem); } } break; case CLEAR_TIMEOUT_CACHES: clearTimeOutCaches(); break; case SEEK: Long seekMills = (Long) msg.obj; if (seekMills != null) { mCacheTimer.update(seekMills.longValue()); mSeekedFlag = true; evictAllNotInScreen(); resume(); } break; case QUIT: removeCallbacksAndMessages(null); mPause = true; evictAll(); clearCachePool(); this.getLooper().quit(); break; case CLEAR_ALL_CACHES: evictAll(); mCacheTimer.update( mTimer.currMillisecond - mContext.mDanmakuFactory.MAX_DANMAKU_DURATION); mSeekedFlag = true; break; case CLEAR_OUTSIDE_CACHES: evictAllNotInScreen(true); mCacheTimer.update(mTimer.currMillisecond); break; case CLEAR_OUTSIDE_CACHES_AND_RESET: evictAllNotInScreen(true); mCacheTimer.update(mTimer.currMillisecond); requestClear(); break; } }