andriod 基本的直播弹幕实现 (一)

两种实现弹幕功能的方法,其实原理上的差别不大,

第一个方法是小巫见打巫,因为第二方法是我在github

上面集成下来的在功能完善方面是完虐第一个的,第一个方法可以说只是拿来大概的了解它,

这个直播弹幕大概是个什么东西!!

第一个的实现过程:

xml文件:

1.


2.



3.


一共三个。

Activity的实现:

--------------------------------------------------------------------定义控件--------------------------------------------------------------------

/////弹幕部分

private BarrageViewbv;

int count;

private Buttonbtn_send;

-----------------------------------------------------------------设置监听--------------------------------------------------------------------



--------------------------------------------------设置弹幕内容,并加入BarrageView布局中-------------------------------------

主要实现的两个类:

-----------------------------------------------------------BarrageLine ----------------------------------------------


package net.ossrs.yasea.demo.Activity.View;

import android.content.Context;

import android.os.Handler;

import android.os.Looper;

import android.util.AttributeSet;

import android.view.View;

import android.widget.FrameLayout;

import java.util.concurrent.ConcurrentLinkedQueue;

public class BarrageLine extends FrameLayout

{

private HandlermHandler;

private ConcurrentLinkedQueuemQueue =new ConcurrentLinkedQueue<>();

private int mWidth;

private int PADDING =20;

private int HEIGHT =100;

// /**

// * 统一线程池

// */

// public static Executor mExecutor = Executors.newCachedThreadPool();

    public BarrageLine(Context context) {

this(context,null);

}

public BarrageLine(Context context, AttributeSet attrs) {

this(context, attrs,0);

}

public BarrageLine(Context context, AttributeSet attrs,int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

///LOOPER用来抽取队列里面的东西

        mHandler =new Handler(Looper.getMainLooper());

}

@Override

    protected void onAttachedToWindow() {

super.onAttachedToWindow();

flutter();

}

/**

* 设置一行的宽高

    * @param widthMeasureSpec

    * @param heightMeasureSpec

    */

    @Override

    protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

this.mWidth = MeasureSpec.getSize(widthMeasureSpec);

setMeasuredDimension(mWidth,HEIGHT);

}

/**

* 网队列里添加弹幕view

    * @param view

    */

    public void addBarrage(View view){

mQueue.offer(view);

}

private class AddBarrageTaskimplements Runnable{

Viewview;

public AddBarrageTask(View view){

this.view = view;

}

@Override

        public void run() {

mQueue.offer(view);

}

}

/**

* 开始执行动画

*/

    private void flutter(){

mHandler.post(mFlutterTask);

}

private RunnablemFlutterTask =new Runnable() {

@Override

        public void run() {

addBarrageView();

moveView();

mHandler.postDelayed(this,5);

}

};

/**

* 判断每一行是否要添加view

*/

    private void addBarrageView() {

if (getChildCount() ==0){

addNextView();

return;

}

View lastChild =this.getChildAt(getChildCount()-1);

int lastChildRight = (int) (lastChild.getTranslationX()+(int)lastChild.getTag());

if (lastChildRight+PADDING>=mWidth)

return;

addNextView();

}

/**

* 给每一行添加view

*/

    private void addNextView(){

if (mQueue.isEmpty())

return;

View view =mQueue.poll();

view.measure(0,0);

view.setTag(view.getMeasuredWidth());

addView(view);

view.setTranslationX(mWidth);

}

/**

* 通过handler.post执行,形成动画

*/

    private void moveView() {

if (this.getChildCount()==0)

return;

for (int i=0;i

View view =this.getChildAt(i);

view.setTranslationX(view.getTranslationX()-3);

if (view.getTranslationX()+(int)view.getTag()<=0)

removeBarrageView(view);

}

}

/**

* 当view移出弹幕行,删除

    * @param view

    */

    private void removeBarrageView(View view){

view.setVisibility(GONE);

this.removeView(view);

view =null;

}

/**

* 停止发消息,取消动画

*/

    private void stop(){

if (mHandler!=null)

mHandler.removeCallbacks(mFlutterTask);

}

@Override

    protected void onDetachedFromWindow() {

super.onDetachedFromWindow();

stop();

}

}

-----------------------------------------------------------BarrageView ----------------------------------------------

package net.ossrs.yasea.demo.Activity.View;

import android.content.Context;

import android.util.AttributeSet;

import android.view.View;

import android.view.ViewGroup;

import android.widget.LinearLayout;

import java.util.ArrayList;

import java.util.Random;

public class BarrageView extends LinearLayout

{

private ArrayListmBarrages =new ArrayList();

private RandommRandom;

public BarrageView(Context context) {

this(context,null);

}

public BarrageView(Context context, AttributeSet attrs) {

this(context, attrs,0);

}

public BarrageView(Context context, AttributeSet attrs,int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

/**

* 总共三行弹幕

*/

    private void init() {

mRandom =new Random();

setOrientation(LinearLayout.VERTICAL);

for (int i =0; i <3; i++) {

BarrageLine bl =new BarrageLine(getContext());

LinearLayout.LayoutParams param =new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

bl.setLayoutParams(param);

this.addView(bl);

mBarrages.add(bl);

}

}

/**

* 随机添加弹幕到某一行

    * @param view

    */

    public void addBarrage(View view) {

mBarrages.get(mRandom.nextInt(3)).addBarrage(view);

}

/**

* 指定添加弹幕到某一行

    * @param view

    * @param line

    */

    public void addBarrage(View view,int line){

mBarrages.get(line).addBarrage(view);

}

}

第一个实现的大致原理:

先认识到这个方法的奇葩的地方:就是Textview转view那部分,如果他的布局不是用TextView开始的话,那么就会报错

Imageview哪里也是一样的,这个涉及到View的加载机制了!有兴趣的可以去了解一下,不过可以确定一点,就是xml文件的属性

是通过加载是的第一个确定的(如果没想起了解的想法的,可以先这样认为)。

然后这里要将几个阅读别人源码是的一些小技巧:

开始时的第一个眼神该放在它是否继承了什么还是说他就是一个简单的工具类。




比如这个,继承的是LinearLayout,说明它是在这个的基础上打造的,就会拥有它父类的特性

然后,就需要你去看他是如何调用的了,特别是在看一个装了很多功能的模块的时候,

因为你是为了某项需求而去看的,为了实现才去了解,所以你甚至不需要完全的了解它(如果你的时间真的说可以的话,

那也不是不可以)。




很明显,我们的起点可以从这里出发。然后顺着它,我们来到了这里


这里我们可以看出addBarrage这个方法来自mBarrages,而且这个mBarrages有get这个方法的,说明它可能是个list集合。

这是就可以得出一个初步的想法,传过来的view被mBarrages.addBarrage调用(而且还是被这个集合里面的随机其中一个调用的)。



然后,我们在看看BarrageView,我们的界面控件。因为是BarrageView实例化后调用的addgarrage,所以,我们也需要了解


主要看这一行,如果是其他的话,估计需要找一下(或者全部知道它),因为这里就只有这一行是信息量最大的,如果你提前看了他是继承什么的,那这个看起来一

点都不难理解,不过读的时候就有点麻烦,因为如果是按这个步骤来读,对于BarrageLine的信息是零,所以我们需要去了解一下BarrageLine

最好带着疑问去,比如:结合前面的mBarrages.addBarrage方法,所以我们点进去后就可以重点关注这个方法究竟是咋样的,这是我们来到了

这里


mQueue.offer(view);很明显这是个加入队列的方法,这里也解释了这一点


到这时,我们有需要了解一下BarrageLine是如何工作的了,因为他在实例化之后加入了我们的BarrageView,所以需要了解它。

如果说要哪里入手的话就有点难讲了,毕竟我们从上一个类哪里得到的信息是,那个集合里面的它取到了一个view,

而且被循环了三次之后被加入了

BarrageView,而且,从他的对齐方式可以大致的想到。。。他应该是这样的


接下来可以说方向就是理解这个view ,他传进去后是如何是BarrageLine起作用的


 


这里指的了解一下的是Looper是负责抽取队列里面的东西的


 

 

很明显这里是判断是否需要addNextView();的


而这个就已经体现了我们view的作用了,他从队列里取了出来,这时view便可以显示出来了(如果你问它怎么就显示出来了,其实是因为

addview这个方法,FragmentLayout属于ViewGroup的布局,这就是为什么在所有开始之前先看他究竟继承了什么。所以他可以调用

viewgroup方法),其他部分的无非是销毁view,停止啊,在个个周期之内需要怎么做的处理。

总结:其实第一个方法贯穿这个功能实现的整个过程的就是那个view,一步一步的顺着线索往下找,就可以找到最终它无非是通过BarrageLine

的方法加入队列之后被addBarrageView()--》addNextView()取出,然后随即的出现在三行BarrageView里面的BarrageLine里面而已。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容