标签:++ seconds sso draw ons call hash cal rda
Android弹幕实现:基于B站弹幕开源系统(2)
在附录1的基础上,模拟实现一种实际开发的应用场景:从网络中不间断的周期取弹幕数据,这些弹幕数据往往是批量的,然后把这些从网络中取到的批量数据逐个的显示出来。注意本例中的Handler和线程安全队列ConcurrentLinkedQueue的使用。
Java代码:
package zhangphil.danmaku; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import master.flame.danmaku.danmaku.model.BaseDanmaku; import master.flame.danmaku.danmaku.model.DanmakuTimer; import master.flame.danmaku.danmaku.model.IDisplayer; import master.flame.danmaku.danmaku.model.android.DanmakuContext; import master.flame.danmaku.ui.widget.DanmakuView; public class MainActivity extends Activity { private DanmakuView mDanmakuView; private DanmakuContext mContext; private AcFunDanmakuParser mParser; private ScheduledThreadPoolExecutor mScheduledThreadPoolExecutor = null; private ConcurrentLinkedQueue<String> mQueue = null; private final int WHAT_GET_LIST_DATA = 0xffa01; private final int WHAT_DISPLAY_SINGLE_DANMAKU = 0xffa02; private final int[] colors = {Color.RED, Color.YELLOW, Color.BLUE, Color.GREEN, Color.CYAN, Color.DKGRAY}; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case WHAT_GET_LIST_DATA: handler.removeMessages(WHAT_GET_LIST_DATA); ArrayList lists = (ArrayList) msg.obj; if (lists != null && !lists.isEmpty()) { mQueue.addAll(lists); if (!mQueue.isEmpty()) handler.sendEmptyMessage(WHAT_DISPLAY_SINGLE_DANMAKU); } break; case WHAT_DISPLAY_SINGLE_DANMAKU: handler.removeMessages(WHAT_DISPLAY_SINGLE_DANMAKU); displayDanmaku(); break; } } }; private void displayDanmaku() { String s = mQueue.poll(); if (!TextUtils.isEmpty(s)) { addDanmaku(s, true); } if (!mQueue.isEmpty()) handler.sendEmptyMessageDelayed(WHAT_DISPLAY_SINGLE_DANMAKU, (long) (Math.random() * 400) + 100); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mQueue = new ConcurrentLinkedQueue<>(); mDanmakuView = (DanmakuView) findViewById(R.id.danmakuView); init(); mScheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1); GetDanmakuMessageTask mTask = new GetDanmakuMessageTask(); //延迟0秒执行,每隔若干秒周期执行一次任务 mScheduledThreadPoolExecutor.scheduleAtFixedRate(mTask, 0, 5, TimeUnit.SECONDS); Button show = (Button) findViewById(R.id.show); Button hide = (Button) findViewById(R.id.hide); Button sendText = (Button) findViewById(R.id.sendText); Button pause = (Button) findViewById(R.id.pause); Button resume = (Button) findViewById(R.id.resume); Button clear = (Button) findViewById(R.id.clear); show.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mDanmakuView.show(); } }); hide.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mDanmakuView.hide(); } }); sendText.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //每点击一次按钮发送一条弹幕 sendTextMessage(); } }); pause.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mDanmakuView.pause(); } }); resume.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mDanmakuView.resume(); } }); clear.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { clearDanmaku(); } }); } /** * 假设该线程任务模拟的就是从网络中取弹幕数据的耗时操作 * */ private class GetDanmakuMessageTask implements Runnable { @Override public void run() { try { Thread.sleep((long) (Math.random() * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } ArrayList<String> danmakuLists = new ArrayList<>(); int count = (int) (Math.random() * 100); for (int i = 0; i < count; i++) { danmakuLists.add("批量数据" + i + " - " + Math.random()); } if (!danmakuLists.isEmpty()) { Message msg = handler.obtainMessage(); msg.what = WHAT_GET_LIST_DATA; msg.obj = danmakuLists; handler.sendMessage(msg); } } } private void clearDanmaku() { mQueue.clear(); mDanmakuView.clearDanmakusOnScreen(); } private void init() { mContext = DanmakuContext.create(); // 设置最大显示行数 HashMap<Integer, Integer> maxLinesPair = new HashMap<>(); maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 8); // 滚动弹幕最大显示5行 // 设置是否禁止重叠 HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<>(); overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true); overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true); mContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 10) //描边的厚度 .setDuplicateMergingEnabled(false) .setScrollSpeedFactor(1.2f) //弹幕的速度。注意!此值越小,速度越快!值越大,速度越慢。// by phil .setScaleTextSize(1.2f) //缩放的值 //.setCacheStuffer(new SpannedCacheStuffer(), mCacheStufferAdapter) // 图文混排使用SpannedCacheStuffer // .setCacheStuffer(new BackgroundCacheStuffer()) // 绘制背景使用BackgroundCacheStuffer .setMaximumLines(maxLinesPair) .preventOverlapping(overlappingEnablePair); mParser = new AcFunDanmakuParser(); mDanmakuView.prepare(mParser, mContext); //mDanmakuView.showFPS(true); mDanmakuView.enableDanmakuDrawingCache(true); if (mDanmakuView != null) { mDanmakuView.setCallback(new master.flame.danmaku.controller.DrawHandler.Callback() { @Override public void updateTimer(DanmakuTimer timer) { } @Override public void drawingFinished() { } @Override public void danmakuShown(BaseDanmaku danmaku) { Log.d("弹幕文本", "danmakuShown text=" + danmaku.text); } @Override public void prepared() { mDanmakuView.start(); } }); } } private void sendTextMessage() { addDanmaku("zhangphil @ csdn : " + System.currentTimeMillis(), true); } private void addDanmaku(CharSequence txt, boolean islive) { BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL); if (danmaku == null || mDanmakuView == null) { return; } danmaku.text = txt; danmaku.padding = 5; danmaku.priority = 0; // 可能会被各种过滤器过滤并隐藏显示 danmaku.isLive = islive; danmaku.setTime(mDanmakuView.getCurrentTime() + 1200); danmaku.textSize = 20f * (mParser.getDisplayer().getDensity() - 0.6f); //文本弹幕字体大小 danmaku.textColor = getRandomColor(); //文本的颜色 danmaku.textShadowColor = getRandomColor(); //文本弹幕描边的颜色 //danmaku.underlineColor = Color.DKGRAY; //文本弹幕下划线的颜色 danmaku.borderColor = getRandomColor(); //边框的颜色 mDanmakuView.addDanmaku(danmaku); } @Override protected void onPause() { super.onPause(); if (mDanmakuView != null && mDanmakuView.isPrepared()) { mDanmakuView.pause(); } } @Override protected void onResume() { super.onResume(); if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) { mDanmakuView.resume(); } } @Override protected void onDestroy() { super.onDestroy(); if (mDanmakuView != null) { // dont forget release! mDanmakuView.release(); mDanmakuView = null; } if (mScheduledThreadPoolExecutor != null) mScheduledThreadPoolExecutor.shutdown(); } /** * 从一系列颜色中随机选择一种颜色 * * @return */ private int getRandomColor() { int i = ((int) (Math.random() * 10)) % colors.length; return colors[i]; } }
代码运行结果:
附录:
1,《Android弹幕实现:基于B站弹幕开源系统(1)》链接地址:http://blog.csdn.net/zhangphil/article/details/68067100
2,《Java ConcurrentLinkedQueue队列线程安全操作》链接地址:http://blog.csdn.net/zhangphil/article/details/65936066
标签:++ seconds sso draw ons call hash cal rda
原文地址:http://blog.csdn.net/zhangphil/article/details/68114226