Android Bullet screen implementation: Based on the B-Station bullet screen Open source System (4)-Refactoring

Source: Internet
Author: User
Tags sendmsg

??

Android Bullet screen implementation: Based on the B-Station bullet screen Open source System (4)-Refactoring

The play screen in the video playback of the app is more common, but the logic is more complex, now on the basis of the appendix, I again on the screen to abstract and re-structure, the barrage from the bottom up into different layers, easy to reuse.

The first step is to abstract the data layer.
Usually the source of the barrage is from the background of the data interface request, in real-time broadcast, is through the network polling mechanism to obtain data, then I drew this part of the code to design a Mgdanmakuhttpcontroller, which focuses on the data acquisition and distribution:

Package Zhangphil.danmaku;import Android.os.handler;import Android.os.message;import Android.support.annotation.nonnull;import Android.util.log;import Java.util.arraylist;import java.util.List; Import Java.util.uuid;import Java.util.concurrent.callable;import Io.reactivex.observable;import Io.reactivex.android.schedulers.androidschedulers;import Io.reactivex.observers.disposableobserver;import Io.reactivex.schedulers.schedulers;import OKHTTP3. Okhttpclient;import OKHTTP3. Request;import OKHTTP3. response;/** * Created by Phil on 2017/3/31. */public class Mgdanmakuhttpcontroller {//private final String TAG = GetClass (). GetName () + string.valueof (uuid.random    UUID ());    private int msgId = 0;    Private Datamessagelistener mdatamessagelistener = null;    Private Okhttpclient mokhttpclient;    Public Mgdanmakuhttpcontroller () {mokhttpclient = new okhttpclient ();    } private Final int what_start = 0xff0a;    Private final int what_stop = What_start + 1; Private Boolean PromIse = false;    private int interval = 0; Private Handler Handler = new Handler () {@Override public void Handlemessage (Message msg) {Supe            R.handlemessage (msg);                if (msg.what = = What_start) {handler.removemessages (What_start);                try {if (promise) Startrequestdanmaku ();                } catch (Exception e) {e.printstacktrace ();    }            }        }    };        public void Startrequestdanmaku () throws Exception {promise = true;            Observable mobservable = observable.fromcallable (new callable<list<danmakumsg>> () {@Override Public list<danmakumsg> Call () throws Exception {//Sync method returns the data results required by the viewer//here to handle threaded            Operation return Fetchdata ();        }}). Subscribeon (Schedulers.io ()). Observeon (Androidschedulers.mainthread ()); MobservablE.subscribe (New disposableobserver<list<danmakumsg>> () {@Override public void OnNext (@N                    Onnull list<danmakumsg> lists) {if (Mdatamessagelistener! = null && promise) {                Mdatamessagelistener.ondatamessagelistener (lists);            }} @Override public void OnComplete () {firerequest ();            } @Override public void OnError (Throwable e) {firerequest ();    }        });    } public void Stoprequestdanmaku () {promise = false; }/** * Set polling interval time * * @param interval unit milliseconds default is 0 */public void sethttprequestinterval (int interval)    {this.interval = interval;        The private void Firerequest () {//here will trigger a restart of the data request, where you can adjust the tempo of the restart data request.    such as can set a certain delay handler.sendemptymessagedelayed (What_start, interval);        } private list<danmakumsg> Fetchdata () {The synchronization method returns the data results required by the viewer//handles threaded operations here//String URL = "Http://blog.csdn.net/zhangphil";//try {// Request Request = new Request.builder (). URL (URL). build ();//Response Response = Mokhttpclient.newcall (Request                ). Execute (),//if (response.issuccessful ()) {//byte[] bytes = response.body (). bytes ();//        String data = new String (bytes, 0, bytes.length);        try {thread.sleep ((int) (Math.random () * 500));        } catch (Interruptedexception e) {e.printstacktrace ();        } int count = (int) (Math.random () * 10);        Assembling analog data list<danmakumsg> danmakumsgs = new arraylist<> ();            for (int i = 0; i < count; i++) {danmakumsg danmakumsg = new Danmakumsg ();            Danmakumsg.msg = string.valueof (msgid++);        Danmakumsgs.add (DANMAKUMSG); } return danmakumsgs;//}//} catch (Exception e) {//E.prinTstacktrace ();//}////return null;    } public interface Datamessagelistener {void Ondatamessagelistener (@NonNull list<danmakumsg> lists);    } public void Setdatamessagelistener (Datamessagelistener listener) {Mdatamessagelistener = listener; }}


The second step, through a model to glue the view and data of the barrage together, I wrote a mgdanmaku:

Package Zhangphil.danmaku;import Android.graphics.color;import Android.os.handler;import android.os.Message;import Android.support.annotation.nonnull;import Android.text.textutils;import Android.util.log;import Java.util.arraylist;import Java.util.hashmap;import Java.util.list;import Java.util.uuid;import Java.util.concurrent.concurrentlinkedqueue;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;/** * Created by Phil on 2017/4/1.    */public class Mgdanmaku {private final String TAG = GetClass (). GetName () + Uuid.randomuuid ();    Private Mgdanmakuhttpcontroller Mmgdanmakuhttpcontroller;    Private Danmakuview Mdanmakuview;    Private Acfundanmakuparser Mparser;    Private Danmakucontext Mdanmakucontext; Private final int max_danmaku_lines = 8; Maximum number of rows displayed on the screen by the barrage   Private concurrentlinkedqueue<danmakumsg> mqueue = null; All the barrage data access queues, where the thread's bounce is taken and stored private arraylist<danmakumsg> danmakulists = null;//cache the list private FINA every time the latest barrage data is requested    l int what_get_list_data = 0XFFAB01;    Private final int what_display_single_danmaku = 0XFFAB02;            /** * Each screen of the various colors from here randomly selected A */private final int[] colors = {color.red, color.yellow,    Color.Blue, Color.green, Color.cyan, Color.dkgray};    Toggle Screen Switch Total control//True normal display and request//False to cancel private Boolean isdanmukuenable = false; Public Mgdanmaku (@NonNull danmakuview view, @NonNull Mgdanmakuhttpcontroller Controller) {This.mdanmakuview = view        ;        This.mmgdanmakuhttpcontroller = Controller;        Initdanmaku ();        danmakulists = new arraylist<> ();        Mqueue = new concurrentlinkedqueue<> (); Mmgdanmakuhttpcontroller.setdatamessagelistener (New Mgdanmakuhttpcontroller.datamessagelistener () {           @Override public void Ondatamessagelistener (@NonNull list<danmakumsg> lists) {                Danmakulists = (arraylist<danmakumsg>) lists;                for (int i = 0; i < danmakulists.size (); i++) {//LOG.D ("Get Data", Danmakulists.get (i). msg);            } addlistdata ();        }        });    LOG.D (GetClass (). GetName (), TAG);            } private Handler Mdanmakuhandler = new Handler () {@Override public void Handlemessage (Message msg) {            Super.handlemessage (msg);                    Switch (msg.what) {case what_get_list_data:addlistdata ();                Break                    Case WHAT_DISPLAY_SINGLE_DANMAKU:mDanmakuHandler.removeMessages (What_display_single_danmaku);                    Displaydanmaku ();            Break    }        }    }; private void Addlistdata () {if (danmakulists! = null &&!danmakulists.isempty ()) {mdanmakuhandler.removemessages (what_get_list_data);            Mqueue.addall (danmakulists);            Danmakulists.clear ();        Mdanmakuhandler.sendemptymessage (What_display_single_danmaku); }} private void Initdanmaku () {//Set maximum number of rows Hashmap<integer, integer> maxlinespair = new Hashma        P<> (); Maxlinespair.put (BASEDANMAKU.TYPE_SCROLL_RL, max_danmaku_lines);        Maximum display of the rolling barrage 5 lines//Set whether to prohibit overlapping hashmap<integer, boolean> Overlappingenablepair = new hashmap<> ();        Overlappingenablepair.put (BASEDANMAKU.TYPE_SCROLL_RL, true);        Overlappingenablepair.put (Basedanmaku.type_fix_top, true);        Mdanmakucontext = Danmakucontext.create (); Normal text bullet screen also stroke set style//If it is a graphic mixed orchestration, and finally do not stroke Mdanmakucontext.setdanmakustyle (Idisplayer.danmaku_style_stroken, 10)/ /stroke thickness. setduplicatemergingenabled (false). Setscrollspeedfactor (1.2f)//The speed of the barrage. Attention! This value is moreSmall, Faster! The higher the value, the slower the speed. by Phil Setscaletextsize (1.2f)//Scaled value//. Setcachestuffer (New Backgroundcachestuffer ())//Draw background Use Backgroundcachestuffer. Setmaximumlines (Maxlinespair). preventoverlapping (overlappingenabl        Epair);        Mparser = new Acfundanmakuparser ();        Mdanmakuview.prepare (Mparser, Mdanmakucontext);        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 Vo                ID Danmakushown (Basedanmaku danmaku) {log.d ("Bullet screen Text", "show text=" + Danmaku.text); } @Override public void PREpared () {Mdanmakuview.start ();        }            });        }}/** * Drive the bullet screen display mechanism to function again */private void Startdanmaku () {mdanmakuview.show ();        Mdanmakuview.start ();        Mdanmakuhandler.sendemptymessage (What_get_list_data);    Mdanmakuhandler.sendemptymessage (What_display_single_danmaku);            } private void Stopdanmaku () {if (Mdanmakuview! = null) {mdanmakuview.hide ();            Mdanmakuview.cleardanmakusonscreen ();        Mdanmakuview.clear ();        } mdanmakuhandler.removemessages (What_get_list_data);        Mdanmakuhandler.removemessages (What_display_single_danmaku);        Danmakulists.clear ();    Mqueue.clear ();            public void Setdanmakurunning (Boolean enable) {//If it is a repeating setting, skip if (isdanmukuenable = = enable) {        Return        } this.isdanmukuenable = enable;        LOG.D ("Isdanmukuenable", String.valueof (isdanmukuenable)); if (Isdanmukuenable) {Startdanmaku ();            try {Mmgdanmakuhttpcontroller.startrequestdanmaku ();            } catch (Exception e) {e.printstacktrace ();            }} else {Stopdanmaku ();        Mmgdanmakuhttpcontroller.stoprequestdanmaku ();    }} public Boolean getdanmakurunning () {return isdanmukuenable;    } public void sendmsg (@NonNull danmakumsg danmakumsg) {Displaydanmaku (danmakumsg); } public void Onresume () {if (Mdanmakuview! = null && mdanmakuview.isprepared () && Mdanmakuview        . ispaused ()) {mdanmakuview.resume (); }} public void OnPause () {if (Mdanmakuview! = null && mdanmakuview.isprepared ()) {MDANM        Akuview.pause ();            }} public void OnDestroy () {if (Mdanmakuview! = null) {//dont forget release!            Mdanmakuview.release ();        Mdanmakuview = null;        }Stopdanmaku (); } private void Displaydanmaku (@NonNull danmakumsg DM) {//If the current pop-up is in a paused state due to the Android life cycle, you should not keep consuming the barrage data// To know that a handler message is sent here, then the Concurrentlinkedqueue header data will be consumed (deleted) if (isdanmukuenable) {if (!            Textutils.isempty (dm.msg)) {Adddanmaku (dm.msg, dm.islive); }}} private void Displaydanmaku () {//If the current pop-up is in a paused state due to the Android life cycle, you should not keep consuming the barrage data//to know that        Out a handler message, then the data that will be consumed (erased) Concurrentlinkedqueue the head is Boolean B =!mqueue.isempty () && getdanmakurunning ();            if (b) {danmakumsg DM = Mqueue.poll (); if (!            Textutils.isempty (dm.msg)) {Adddanmaku (dm.msg, dm.islive); }}} private void Adddanmaku (Charsequence cs, Boolean islive) {Basedanmaku Danmaku = Mdanmakucontext        . Mdanmakufactory.createdanmaku (BASEDANMAKU.TYPE_SCROLL_RL);        if (Danmaku = = NULL | | mdanmakuview = = NULL) {return;      }  Danmaku.text = CS;        danmaku.padding = 5;  danmaku.priority = 0;        May be filtered by various filters and hidden display danmaku.islive = islive;        Danmaku.settime (Mdanmakuview.getcurrenttime ()); Danmaku.textsize = 20f * (Mparser.getdisplayer (). Getdensity ()-0.6f); Text bullet screen font size Danmaku.textcolor = Getrandomcolor (); The color of the text Danmaku.textshadowcolor = Getrandomcolor (); Text Bullet screen stroke color//danmaku.underlinecolor = Color.dkgray; Text bullet screen underline color danmaku.bordercolor = Getrandomcolor ();    The color of the Border Mdanmakuview.adddanmaku (Danmaku); }/** * Randomly select a color from a range of colors * * @return */private int getrandomcolor () {int i = ((int) (Math.ra        Ndom () *)% Colors.length;    return colors[i]; }}



The third step is to take the activity in the upper level directly:

Package Zhangphil.danmaku;import Android.app.activity;import Android.os.bundle;import android.util.Log;import Android.view.view;import Android.widget.button;import Android.widget.checkbox;import Android.widget.compoundbutton;import Master.flame.danmaku.ui.widget.danmakuview;public class MainActivity extends    Activity {private Mgdanmaku Mmgdanmaku;        @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);        Setcontentview (R.layout.activity_main);        LOG.D (GetClass (). GetName (), "onCreate");        Danmakuview Mdanmakuview = (danmakuview) Findviewbyid (R.id.danmakuview);        Mgdanmakuhttpcontroller Mmgdanmakuhttpcontroller = new Mgdanmakuhttpcontroller ();        Mmgdanmakuhttpcontroller.sethttprequestinterval (0);        Mmgdanmaku = new Mgdanmaku (Mdanmakuview, Mmgdanmakuhttpcontroller);        CheckBox checkbox = (checkbox) Findviewbyid (R.id.checkbox);        Checkbox.setchecked (Mmgdanmaku.getdanmakurunning ()); ChecKbox.setoncheckedchangelistener (New Compoundbutton.oncheckedchangelistener () {@Override public void            OnCheckedChanged (Compoundbutton Buttonview, Boolean isChecked) {mmgdanmaku.setdanmakurunning (isChecked);        }        });        Button SendText = (button) Findviewbyid (R.id.sendtext);                Sendtext.setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View v) {                danmakumsg msg = new Danmakumsg ();                Msg.msg = "Zhangphil:" + system.currenttimemillis ();            Mmgdanmaku.sendmsg (msg);    }        });        } @Override protected void Onresume () {super.onresume ();    Mmgdanmaku.onresume ();        } @Override protected void OnPause () {super.onpause ();    Mmgdanmaku.onpause ();        } @Override protected void OnDestroy () {Super.ondestroy ();    Mmgdanmaku.ondestroy (); }}



A simple bullet-screen data message package:

Package zhangphil.danmaku;/** * Created by Phil on 2017/3/31. */import java.io.serializable;/** * Bullet screen Data encapsulated Class (bean) */public class Danmakumsg implements Serializable {public    String id = "";    Public String msg = NULL;    public Boolean islive = true;    Public String point = "";}



Test the mainactivity layout file:

<?xml version= "1.0" encoding= "Utf-8"? ><linearlayout xmlns:android= "http://schemas.android.com/apk/res/ Android "    android:layout_width=" match_parent "    android:layout_height=" match_parent "    android:o rientation= "vertical" >    <checkbox        android:id= "@+id/checkbox" android:layout_width= "Match_        Parent "        android:layout_height=" wrap_content "        android:text=" flick switch "/>    <button        android:id=" @ +id/sendtext "        android:layout_width=" wrap_content "        android:layout_height=" Wrap_content "        android: text= "Send text barrage"/>    <master.flame.danmaku.ui.widget.danmakuview        android:id= "@+id/danmakuview"        android:layout_width= "match_parent"        android:layout_height= "Match_parent"/></linearlayout>


Attention! It is necessary to configure the activity in the Androidmanifest.xml properties Configchanges and Launchmode to accommodate the correct state of the barrage when switching between the screen and landscape, such as:

<activity android:name= ". Mainactivity "            android:configchanges=" Orientation|keyboardhidden|screensize|fontscale "            android: Launchmode= "Singletask" >            <intent-filter>                <action android:name= "Android.intent.action.MAIN"/ >                <category android:name= "Android.intent.category.LAUNCHER"/>            </intent-filter>


Code Run Results


Appendix:
1, "Android Bullet screen realization: Based on the B-Station bullet screen Open source system (1)" Link: http://blog.csdn.net/zhangphil/article/details/68067100
2, "Android Bullet screen realization: Based on the B-Station bullet screen Open source system (2)" Link: http://blog.csdn.net/zhangphil/article/details/68114226
3, "Android Bullet screen realization: Based on the B-Station bullet screen Open source System (3)-text barrage perfect and detail adjustment" Link: http://blog.csdn.net/zhangphil/article/details/68485505
4, "Java concurrentlinkedqueue queue thread safe operation" Link: http://blog.csdn.net/zhangphil/article/details/65936066

Android Bullet screen implementation: Based on the B-Station bullet screen Open source System (4)-Refactoring

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.