public boolean createCache(BaseDanmaku item) {
   // measure
   if (!item.isMeasured()) {
     item.measure(mDisp);
   }
   DrawingCache cache = null;
   try {
     cache = mCachePool.acquire();
     cache = DanmakuUtils.buildDanmakuDrawingCache(item, mDisp, cache);
     item.cache = cache;
   } catch (OutOfMemoryError e) {
     // Log.e("cache", "break at error: oom");
     if (cache != null) {
       mCachePool.release(cache);
     }
     item.cache = null;
     return false;
   } catch (Exception e) {
     // Log.e("cache", "break at exception:" + e.getMessage());
     if (cache != null) {
       mCachePool.release(cache);
     }
     item.cache = null;
     return false;
   }
   return true;
 }
 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;
 }
Exemple #3
0
  @Override
  public IDanmakus sub(long startTime, long endTime) {
    if (mSortType == ST_BY_LIST || items == null || items.size() == 0) {
      return null;
    }
    if (subItems == null) {
      subItems = new Danmakus(mDuplicateMergingEnabled);
    }
    if (startItem == null) {
      startItem = createItem("start");
    }
    if (endItem == null) {
      endItem = createItem("end");
    }

    if (subItems != null) {
      long dtime = startTime - startItem.time;
      if (dtime >= 0 && endTime <= endItem.time) {
        return subItems;
      }
    }

    startItem.time = startTime;
    endItem.time = endTime;
    subItems.setItems(((SortedSet<BaseDanmaku>) items).subSet(startItem, endItem));
    return subItems;
  }
 public void addDanmaku(BaseDanmaku item) {
   if (drawTask != null) {
     item.flags = mContext.mGlobalFlagValues;
     item.setTimer(timer);
     drawTask.addDanmaku(item);
     obtainMessage(NOTIFY_RENDERING).sendToTarget();
   }
 }
 private long clearCache(BaseDanmaku oldValue) {
   if (oldValue.cache.hasReferences()) {
     oldValue.cache.decreaseReference();
     oldValue.cache = null;
     return 0;
   }
   long size = sizeOf(oldValue);
   oldValue.cache.destroy();
   oldValue.cache = null;
   return size;
 }
  public static void fillText(BaseDanmaku danmaku, String text) {
    danmaku.text = text;
    if (TextUtils.isEmpty(text) || !text.contains(BaseDanmaku.DANMAKU_BR_CHAR)) {
      return;
    }

    String[] lines = danmaku.text.split(BaseDanmaku.DANMAKU_BR_CHAR, -1);
    if (lines.length > 1) {
      danmaku.lines = lines;
    }
  }
Exemple #7
0
 @Override
 public int compare(BaseDanmaku obj1, BaseDanmaku obj2) {
   if (mDuplicateMergingEnable && DanmakuUtils.isDuplicate(obj1, obj2)) {
     return 0;
   }
   int result = Float.compare(obj2.getTop(), obj1.getTop());
   if (result != 0) {
     return result;
   }
   return DanmakuUtils.compare(obj1, obj2);
 }
 @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;
   }
 }
 @Override
 public void addDanmaku(BaseDanmaku item) {
   if (danmakuList == null) return;
   synchronized (danmakuList) {
     if (item.isLive) {
       removeUnusedLiveDanmakusIn(5);
     }
     item.setTimer(mTimer);
     item.index = danmakuList.size();
     danmakuList.addItem(item);
   }
 }
Exemple #10
0
 @Override
 public boolean removeItem(BaseDanmaku item) {
   if (item == null) {
     return false;
   }
   if (item.isOutside()) {
     item.setVisibility(false);
   }
   if (items.remove(item)) {
     mSize--;
     return true;
   }
   return false;
 }
 protected void removeUnusedLiveDanmakusIn(int msec) {
   if (danmakuList == null || danmakuList.isEmpty()) return;
   long startTime = System.currentTimeMillis();
   IDanmakuIterator it = danmakuList.iterator();
   while (it.hasNext()) {
     BaseDanmaku danmaku = it.next();
     if (danmaku.isLive && danmaku.isTimeOut()) {
       it.remove();
     }
     if (System.currentTimeMillis() - startTime > msec) {
       break;
     }
   }
 }
 @Override
 public void releaseResource(BaseDanmaku danmaku) {
   // TODO 重要:清理含有ImageSpan的text中的一些占用内存的资源 例如drawable
   if (danmaku.text instanceof Spanned) {
     danmaku.text = "";
   }
 }
 protected synchronized void removeUnusedLiveDanmakusIn(int msec) {
   if (danmakuList == null || danmakuList.isEmpty()) return;
   long startTime = System.currentTimeMillis();
   IDanmakuIterator it = danmakuList.iterator();
   while (it.hasNext()) {
     BaseDanmaku danmaku = it.next();
     boolean isTimeout = danmaku.isTimeOut();
     if (isTimeout && danmaku.isLive) {
       it.remove();
       onDanmakuRemoved(danmaku);
     }
     if (!isTimeout || System.currentTimeMillis() - startTime > msec) {
       break;
     }
   }
 }
 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);
   }
 }
Exemple #15
0
  private Collection<BaseDanmaku> subset(long startTime, long endTime) {
    if (mSortType == ST_BY_LIST || items == null || items.size() == 0) {
      return null;
    }
    if (subItems == null) {
      subItems = new Danmakus(mDuplicateMergingEnabled);
    }
    if (startSubItem == null) {
      startSubItem = createItem("start");
    }
    if (endSubItem == null) {
      endSubItem = createItem("end");
    }

    startSubItem.time = startTime;
    endSubItem.time = endTime;
    return ((SortedSet<BaseDanmaku>) items).subSet(startSubItem, endSubItem);
  }
 public static void fillLinePathData(
     BaseDanmaku item, float[][] points, float scaleX, float scaleY) {
   if (item.getType() != BaseDanmaku.TYPE_SPECIAL || points.length == 0 || points[0].length != 2)
     return;
   for (int i = 0; i < points.length; i++) {
     points[i][0] *= scaleX;
     points[i][1] *= scaleY;
   }
   ((SpecialDanmaku) item).setLinePathData(points);
 }
 private boolean push(BaseDanmaku item, int itemSize, boolean forcePush) {
   int size = itemSize; // sizeOf(item);
   while (mRealSize + size > mMaxSize && mCaches.size() > 0) {
     BaseDanmaku oldValue = mCaches.first();
     if (oldValue.isTimeOut()) {
       entryRemoved(false, oldValue, item);
       mCaches.removeItem(oldValue);
     } else {
       if (forcePush) {
         break;
       }
       return false;
     }
   }
   this.mCaches.addItem(item);
   mRealSize += size;
   // Log.e("CACHE", "realsize:"+mRealSize + ",size" + size);
   return true;
 }
 private void clearTimeOutCaches(long time) {
   IDanmakuIterator it = mCaches.iterator();
   while (it.hasNext() && !mEndFlag) {
     BaseDanmaku val = it.next();
     if (val.isTimeOut()) {
       synchronized (mDrawingNotify) {
         try {
           mDrawingNotify.wait(30);
         } catch (InterruptedException e) {
           e.printStackTrace();
           break;
         }
       }
       entryRemoved(false, val, null);
       it.remove();
     } else {
       break;
     }
   }
 }
 private void releaseDanmakuCache(BaseDanmaku item, DrawingCache cache) {
   if (cache == null) {
     cache = (DrawingCache) item.cache;
   }
   item.cache = null;
   if (cache == null) {
     return;
   }
   cache.destroy();
   mCachePool.release(cache);
 }
 protected void entryRemoved(boolean evicted, BaseDanmaku oldValue, BaseDanmaku newValue) {
   if (oldValue.cache != null) {
     IDrawingCache<?> cache = oldValue.cache;
     long releasedSize = clearCache(oldValue);
     if (oldValue.isTimeOut()) {
       mContext.getDisplayer().getCacheStuffer().releaseResource(oldValue);
     }
     if (releasedSize <= 0) return;
     mRealSize -= releasedSize;
     mCachePool.release((DrawingCache) cache);
   }
 }
 @Override
 public void addDanmaku(BaseDanmaku danmaku) {
   if (mHandler != null) {
     if (danmaku.isLive) {
       if (danmaku.isTimeOut()) {
         return;
       }
       mHandler.createCache(danmaku);
     } else {
       mHandler.obtainMessage(CacheHandler.ADD_DANMAKKU, danmaku).sendToTarget();
     }
   }
 }
 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;
 }
  @OnClick(R.id.danmu_add)
  void addDanmu() {
    i++;
    BaseDanmaku danmaku = danmukuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);

    Log.d("tag", "测试用弹幕 + " + i + "条");
    danmaku.text = "测试用弹幕 + " + i + "条";

    danmaku.padding = 10;
    danmaku.priority = 1; // 1:一定会显示, 一般用于本机发送的弹幕,但会导致行数的限制失效
    danmaku.isLive = false;
    danmaku.textSize = 20;
    danmaku.textColor = Color.WHITE;
    danmaku.textShadowColor = 0; // 重要:如果有图文混排,最好不要设置描边(设textShadowColor=0),否则会进行两次复杂的绘制导致运行效率降低
    danmakuView.addDanmaku(danmaku);
  }
 /**
  * Initial translation data of the special danmaku
  *
  * @param item
  * @param dispWidth
  * @param dispHeight
  * @param beginX
  * @param beginY
  * @param endX
  * @param endY
  * @param translationDuration
  * @param translationStartDelay
  */
 public static void fillTranslationData(
     BaseDanmaku item,
     float beginX,
     float beginY,
     float endX,
     float endY,
     long translationDuration,
     long translationStartDelay,
     float scaleX,
     float scaleY) {
   if (item.getType() != BaseDanmaku.TYPE_SPECIAL) return;
   ((SpecialDanmaku) item)
       .setTranslationData(
           beginX * scaleX,
           beginY * scaleY,
           endX * scaleX,
           endY * scaleY,
           translationDuration,
           translationStartDelay);
   updateSpecicalDanmakuDuration(item);
 }
 @Override
 public synchronized void addDanmaku(BaseDanmaku item) {
   if (danmakuList == null) return;
   boolean added = false;
   if (item.isLive) {
     removeUnusedLiveDanmakusIn(10);
   }
   item.index = danmakuList.size();
   if (mLastBeginMills <= item.time && item.time <= mLastEndMills) {
     synchronized (danmakus) {
       added = danmakus.addItem(item);
     }
   } else if (item.isLive) {
     mLastBeginMills = mLastEndMills = 0;
   }
   synchronized (danmakuList) {
     added = danmakuList.addItem(item);
   }
   if (added && mTaskListener != null) {
     mTaskListener.onDanmakuAdd(item);
   }
 }
 /**
  * Initial alpha data of the special danmaku
  *
  * @param item
  * @param beginAlpha
  * @param endAlpha
  * @param alphaDuraion
  */
 public static void fillAlphaData(
     BaseDanmaku item, int beginAlpha, int endAlpha, long alphaDuraion) {
   if (item.getType() != BaseDanmaku.TYPE_SPECIAL) return;
   ((SpecialDanmaku) item).setAlphaData(beginAlpha, endAlpha, alphaDuraion);
   updateSpecicalDanmakuDuration(item);
 }
 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;
   }
 }
      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;
      }
      private byte buildCache(BaseDanmaku item, boolean forceInsert) {

        // measure
        if (!item.isMeasured()) {
          item.measure(mDisp);
        }

        DrawingCache cache = null;
        try {
          // try to find reuseable cache
          BaseDanmaku danmaku = findReuseableCache(item, true, 20);
          if (danmaku != null) {
            cache = (DrawingCache) danmaku.cache;
          }
          if (cache != null) {
            cache.increaseReference();
            item.cache = cache;
            // Log.w("cache", danmaku.text + "DrawingCache hit!!:" + item.paintWidth + "," +
            // danmaku.paintWidth);
            mCacheManager.push(item, 0, forceInsert);
            return RESULT_SUCCESS;
          }

          // try to find reuseable cache from timeout || no-refrerence caches
          danmaku = findReuseableCache(item, false, 50);
          if (danmaku != null) {
            cache = (DrawingCache) danmaku.cache;
          }
          if (cache != null) {
            danmaku.cache = null;
            // Log.e("cache", danmaku.text + "DrawingCache hit!!:" + item.paintWidth + "," +
            // danmaku.paintWidth);
            cache = DanmakuUtils.buildDanmakuDrawingCache(item, mDisp, cache); // redraw
            item.cache = cache;
            mCacheManager.push(item, 0, forceInsert);
            return RESULT_SUCCESS;
          }

          // guess cache size
          if (!forceInsert) {
            int cacheSize =
                DanmakuUtils.getCacheSize((int) item.paintWidth, (int) item.paintHeight);
            if (mRealSize + cacheSize > mMaxSize) {
              //                        Log.d("cache", "break at MaxSize:"+mMaxSize);
              return RESULT_FAILED;
            }
          }

          cache = mCachePool.acquire();
          cache = DanmakuUtils.buildDanmakuDrawingCache(item, mDisp, cache);
          item.cache = cache;
          boolean pushed = mCacheManager.push(item, sizeOf(item), forceInsert);
          if (!pushed) {
            releaseDanmakuCache(item, cache);
            // Log.e("cache", "break at push failed:" + mMaxSize);
          }
          return pushed ? RESULT_SUCCESS : RESULT_FAILED;

        } catch (OutOfMemoryError e) {
          // Log.e("cache", "break at error: oom");
          releaseDanmakuCache(item, cache);
          return RESULT_FAILED;
        } catch (Exception e) {
          // Log.e("cache", "break at exception:" + e.getMessage());
          releaseDanmakuCache(item, cache);
          return RESULT_FAILED;
        }
      }