android 弹幕b站,Android弹幕实现:基于B站弹幕开源系统(2)



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 ConcurrentLinkedQueuemQueue = 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();

}

ArrayListdanmakuLists = 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();

// 设置最大显示行数

HashMapmaxLinesPair = new HashMap<>();

maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 8); // 滚动弹幕最大显示5行

// 设置是否禁止重叠

HashMapoverlappingEnablePair = 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];

}

}

代码运行结果:

13e7a1b09d3b3f6d4577ae9b931265d4.png

附录:

1,《Android弹幕实现:基于B站弹幕开源系统(1)》链接地址:http://blog.csdn.net/zhangphil/article/details/68067100

2,《Java ConcurrentLinkedQueue队列线程安全操作》链接地址:http://blog.csdn.net/zhangphil/article/details/65936066

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值