bilibili删掉了DanmakuFlameMaster源码里的AcFunDanmakuParser,之前官方(包括目前网上各种教程里的AcFunDanmakuParser)也已经不适用,而官方给我们的BiliDanmukuParser不支持json,因此我重写了一个支持json的AcFunDanmakuParser,支持的json格式为A站默认的json格式
[{"c":"0,16777215,1,25,196050,1364468342","m":"弹幕弹幕弹幕"},{"c":"3.619,16777215,1,25,196050,1364468347","m":"弹幕弹幕弹幕弹幕弹幕弹幕"}]
参数:{"c": "播放时间,颜色,模式,字号,uid,发送时间", "m": "弹幕内容"}
其中uid和发送时间可以自定义,由自己判断是否需要改变弹幕样式
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.graphics.Color;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
import master.flame.danmaku.danmaku.parser.android.JSONSource;
public class AcFunDanmakuParser extends BaseDanmakuParser {
@Override
public Danmakus parse() {
if (mDataSource != null && mDataSource instanceof JSONSource) {
JSONSource jsonSource = (JSONSource) mDataSource;
return doParse(jsonSource.data());
}
return new Danmakus();
}
/**
* @param danmakuListData 弹幕数据
* 传入的数组内包含普通弹幕,会员弹幕,锁定弹幕。
* @return 转换后的Danmakus
*/
private Danmakus doParse(JSONArray danmakuListData) {
Danmakus danmakus = new Danmakus();
if (danmakuListData == null || danmakuListData.length() == 0) {
return danmakus;
}
danmakus = _parse(danmakuListData, danmakus);
return danmakus;
}
private Danmakus _parse(JSONArray jsonArray, Danmakus danmakus) {
if (danmakus == null) {
danmakus = new Danmakus();
}
if (jsonArray == null || jsonArray.length() == 0) {
return danmakus;
}
for (int i = 0; i < jsonArray.length(); i++) {
try {
JSONObject obj = jsonArray.getJSONObject(i);
String c = obj.getString("c");
String[] values = c.split(",");
if (values.length > 0) {
int type = Integer.parseInt(values[2]); // 弹幕类型
if (type == 7)
// FIXME : hard code
// TODO : parse advance danmaku json
continue;
long time = (long) (Float.parseFloat(values[0]) * 1000); // 出现时间
int color = Integer.parseInt(values[1]) | 0xFF000000; // 颜色
float textSize = Float.parseFloat(values[3]); // 字体大小
BaseDanmaku item = mContext.mDanmakuFactory.createDanmaku(type, mContext);
if (item != null) {
item.setTime(time);
item.textSize = textSize * (mDispDensity - 0.6f);
item.textColor = color;
item.textShadowColor = color <= Color.BLACK ? Color.WHITE : Color.BLACK;
item.index = i;
item.flags = mContext.mGlobalFlagValues;
item.setTimer(mTimer);
item.text = obj.getString("m");
danmakus.addItem(item);
}
}
} catch (JSONException e) {
} catch (NumberFormatException e) {
}
}
return danmakus;
}
}
使用的时候可以这样用(参考官方的demo):
private BaseDanmakuParser createParser(InputStream stream) {
if (stream == null) {
return new BaseDanmakuParser() {
@Override
protected Danmakus parse() {
return new Danmakus();
}
};
}
ILoader loader = DanmakuLoaderFactory.create(DanmakuLoaderFactory.TAG_ACFUN);
try {
loader.load(stream);
} catch (IllegalDataException e) {
e.printStackTrace();
}
BaseDanmakuParser parser = new AcFunDanmakuParser();
IDataSource<?> dataSource = loader.getDataSource();
parser.load(dataSource);
return parser;
}
其实也不难理解,从JSONArray里解析出弹幕的内容,颜色,时间,颜色等属性,然后填充进BaseDanmaku里面,再把BaseDanmaku添加进Danmakus里,最后把Danmakus返回回去就行,JSONArray相信大家都懂得,知道这点之后,其实我们也没必要严格遵循官方的格式了。
甚至我们可以重写BaseDanmakuParser、ILoader、IDataSource这三个类,来实现我们自己的Parser,这里我写一个JsonParser供大家参考
import android.graphics.Color;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.videoplayertest.bean.DanmakuBean;
import java.io.Reader;
import java.util.List;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
public class JsonParser extends BaseDanmakuParser {
@Override
protected Danmakus parse() {
Danmakus danmakus = new Danmakus();
if(mDataSource != null && mDataSource instanceof JsonSource){
JsonSource source = (JsonSource) this.mDataSource;
return doParse(source.data());
}
return danmakus;
}
private Danmakus doParse(Reader json) {
Danmakus danmakus = new Danmakus();
//在这里解析json,填充进BaseDanmaku里
Gson gson = new Gson();
List<DanmakuBean> beans = gson.fromJson(json, new TypeToken<List<DanmakuBean>>() {
}.getType());
if(beans != null && beans.size()>0){
int size = beans.size();
for (int i = 0 ; i < size ; i++){
DanmakuBean bean = beans.get(i);
int type = bean.getType();
if (type == 7)
continue;
BaseDanmaku item = mContext.mDanmakuFactory.createDanmaku(type, mContext);
item.flags = mContext.mGlobalFlagValues;
item.textSize = bean.getTextSize() * (mDispDensity - 0.6f);
item.textColor = bean.getTextColor();
item.textShadowColor = bean.getTextColor() <= Color.BLACK ? Color.WHITE : Color.BLACK;
item.setTime((long) (bean.getTime()*1000));
item.setTimer(mTimer);
item.text = bean.getText();
item.index = i;
danmakus.addItem(item);
}
}
return danmakus;
}
}
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import master.flame.danmaku.danmaku.loader.ILoader;
import master.flame.danmaku.danmaku.loader.IllegalDataException;
public class JsonLoader implements ILoader {
private static volatile JsonLoader instance;
private JsonSource source;
public static ILoader instance() {
if(instance == null){
synchronized (JsonLoader.class){
if(instance == null)
instance = new JsonLoader();
}
}
return instance;
}
@Override
public JsonSource getDataSource() {
return source;
}
@Override
public void load(String uri) throws IllegalDataException {
load(new StringReader(uri));
}
@Override
public void load(InputStream in) throws IllegalDataException {
InputStreamReader reader = new InputStreamReader(in);
load(reader);
}
public void load(Reader reader) throws IllegalDataException {
source = new JsonSource(reader);
}
}
import java.io.Reader;
import master.flame.danmaku.danmaku.parser.IDataSource;
/**
* 考虑到弹幕数据可能较多,为避免String溢出,这里建议使用reader代替String
* Gson可以直接使用reader,而且Reader方便在String和InputStream之间转换
*/
public class JsonSource implements IDataSource<Reader> {
Reader reader;
public JsonSource(Reader reader) {
this.reader = reader;
}
@Override
public Reader data() {
return reader;
}
@Override
public void release() {
reader = null;
}
}
使用的时候把InputStream 传进JsonLoader即可
private BaseDanmakuParser createParser(InputStream stream) {
ILoader loader = JsonLoader.instance();
try {
loader.load(stream);
} catch (IllegalDataException e) {
e.printStackTrace();
}
JsonParser parser = new JsonParser();
IDataSource<?> dataSource = loader.getDataSource();
parser.load(dataSource);
return parser;
}
我自定义的json格式为:
[{"millis":0,"text":"弹幕111111","textColor":-65536,"textSize":20.0,"time":0.6,"type":1,"userId":0},{"millis":0,"text":"弹幕111111","textColor":-16776961,"textSize":20.0,"time":0.6,"type":1,"userId":0}]
DanmakuBean为该json的实体类