SurfaceView

View 主要适用于主动更新的状况,而 surfaceView 主要适用于被动更新,例如频繁的刷新。
View 在主线程中对画面进行刷新,而 surfaceView 一般会经过一个子线程来进行页面的刷新
View 在绘图时没有使用双缓冲机制,而 surfaceView 在底层实现机制上就已经实现了双缓冲机制。
总结就是,若是你的自定义 View 须要频繁刷新,或者刷新时数据处理量很大,考虑用 SurfaceView 来替代 View。
//MainAtityjava

package com.example.administrator.myapplication;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SeekBar;

import java.io.IOException;
import java.util.ArrayList;
import java.util.WeakHashMap;

public class MainActivity extends AppCompatActivity implements View.OnClickListener,SurfaceHolder.Callback {
    MediaPlayer mediaPlayer = new MediaPlayer();
    String string = "http://uvideo.spriteapp.cn/video/2019/0512/56488d0a-7465-11e9-b91b-1866daeb0df1_wpd.mp4";
    private SurfaceView surface_view;
    private SurfaceHolder surfaceHolder;
    private SurfaceView surfaceView_danmu;
    private SurfaceHolder surfaceHolder_danmu;
    private SeekBar bar;
    private Button bt_play;
    private Button bt_pause;
    private EditText et;
    private Button bt_danmu;
    int x=0;
    ArrayList<DanMu> list=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initpalyer();
        list.add(new DanMu("张志南好帅啊",0,100,Color.GREEN,10));
        list.add(new DanMu("吴迪最帅好帅啊",0,200,Color.YELLOW,40));
        list.add(new DanMu("高迪最可爱啊",0,300,Color.RED,10));
        list.add(new DanMu("圆圈其真胖啊",0,140,Color.GRAY,30));
        list.add(new DanMu("李卓好丑啊",0,150,Color.BLUE,10));
        list.add(new DanMu("兔爷真高啊",0,240,Color.GREEN,10));

    }

    private void initpalyer() {
        if (mediaPlayer != null) {
            try {
                mediaPlayer.reset();
                mediaPlayer.setDataSource(string);
                mediaPlayer.prepareAsync();
                mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        mediaPlayer.start();
                    }
                });
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void initView() {

        surface_view = (SurfaceView) findViewById(R.id.surface_view);
        surfaceHolder=surface_view.getHolder();
        surfaceHolder.addCallback(this);

        surfaceView_danmu=findViewById(R.id.surface_danmu);
        surfaceHolder_danmu=surfaceView_danmu.getHolder();
        surfaceHolder_danmu.addCallback(this);

        surfaceView_danmu.setZOrderOnTop(true);
        surfaceHolder_danmu.setFormat(PixelFormat.TRANSPARENT);




        bar = (SeekBar) findViewById(R.id.bar);
        bt_play = (Button) findViewById(R.id.bt_play);
        bt_pause = (Button) findViewById(R.id.bt_pause);
        et = (EditText) findViewById(R.id.et);
        bt_danmu = (Button) findViewById(R.id.bt_danmu);

        bt_play.setOnClickListener(this);
        bt_pause.setOnClickListener(this);
        bt_danmu.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt_play:

                break;
            case R.id.bt_pause:

                break;
            case R.id.bt_danmu:
                String string = et.getText().toString();
                list.add(new DanMu(string,0,200,Color.GREEN,70));

                break;
        }
    }


    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if(holder==surfaceHolder){
            mediaPlayer.setDisplay(surfaceHolder);
        }else if(holder==surfaceHolder_danmu){
            new DanMuThread().start();
        }

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }
    class DanMuThread extends Thread{
        @Override
        public void run() {
            super.run();

            Paint paint = new Paint();
            paint.setColor(Color.RED);
            paint.setStrokeWidth(20);
            paint.setTextSize(30);
            while (true){
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                Canvas canvas = surfaceHolder_danmu.lockCanvas();
                if(canvas==null){
                    break;
                }

                canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

                for(int i=0;i<list.size();i++){
                    DanMu danMu = list.get(i);
                    paint.setColor(danMu.getColor());
                    paint.setTextSize(danMu.getSize());
                    int x = danMu.getX();
                    danMu.setX(x+=10);
                    canvas.drawText(danMu.getText(),danMu.getX(),danMu.getY(),paint);
                }

                surfaceHolder_danmu.unlockCanvasAndPost(canvas);
            }

        }
    }
}

//实体类android

package com.example.administrator.myapplication;

public class DanMu {
    private String text;
    private int x;
    private int y;
    private int color;
    private int size;

    public DanMu(String text, int x, int y, int color, int size) {
        this.text = text;
        this.x = x;
        this.y = y;
        this.color = color;
        this.size = size;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }
}

//效果图canvas

//,Main2Activityapp

package com.example.administrator.myapplication.day1704;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.example.administrator.myapplication.R;

import com.google.gson.Gson;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

public class Main2Activity extends AppCompatActivity implements SurfaceHolder.Callback {
    SurfaceView surfaceView;
    SurfaceHolder surfaceHolder;
    ArrayList<Music> list=new ArrayList<>();
    MediaPlayer mediaPlayer=new MediaPlayer();
    int positon=0;
    Timer timer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        initView();
        initMusic();
        initCi();
        initTimer();
    }

    private void initView() {
        surfaceView=findViewById(R.id.surface_view);
        surfaceHolder=surfaceView.getHolder();
        surfaceHolder.addCallback(this);
    }


    private void initTimer() {
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                int currentPosition = mediaPlayer.getCurrentPosition();
                if(list.size()>0){
                    if(currentPosition>=list.get(positon+1).getStart_time()){
                        positon++;
                    }
                }

            }
        },0,500);
    }

    private void initCi() {
        try {
            FileInputStream fileInputStream = new FileInputStream("/sdcard/最炫民族风");
            byte[] bytes=new byte[1024];
            int len=0;
            StringBuilder stringBuilder=new StringBuilder();
            while((len=fileInputStream.read(bytes))!=-1){
                stringBuilder.append(new String(bytes,0,len));
            }

            Gson gson = new Gson();
            Bean bean = gson.fromJson(stringBuilder.toString(), Bean.class);
            String lyric = bean.getLrc().getLyric();

            String[] split1 = lyric.split("\n");
            for(int i=0;i<split1.length;i++){

                String trim = split1[i].trim();
                String[] split = trim.split("]");
                if(split.length>=2){
                    String s = split[0];
                    String substring1 = s.substring(1, 3);
                    String substring2 = s.substring(4, 6);
                    String substring3 = s.substring(7, 10);
                    long start=Integer.parseInt(substring1)*60*1000+Integer.parseInt(substring2)*1000+Integer.parseInt(substring3);
                    String text = split[1];
                    list.add(new Music(text,start));
                }
            }
            for(int i=0;i<list.size();i++){
                Log.d("ytx", "initCi: "+list.get(i));
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void initMusic() {
        if(mediaPlayer!=null){
            mediaPlayer.reset();
            try {
                mediaPlayer.setDataSource("/sdcard/凤凰传奇 - 最炫民族风(Live).mp3");
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                mediaPlayer.prepare();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mediaPlayer.start();
                }
            });
        }

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        new MusicThread().start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

        if(mediaPlayer!=null){
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer=null;
        }

        if(timer!=null){
            timer.cancel();
        }
    }
    class MusicThread extends Thread{
        @Override
        public void run() {
            Paint paint = new Paint();
            paint.setColor(Color.YELLOW);
            paint.setTextSize(50);
            while (true){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Canvas canvas = surfaceHolder.lockCanvas();
                if(canvas==null){
                    break;
                }
                canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

                if(list.size()>0){
                    canvas.drawText(list.get(positon).getText(),200,300,paint);
                }
                surfaceHolder.unlockCanvasAndPost(canvas);
            }

        }
    }
}

//bean类ide

package com.example.administrator.myapplication.day1704;


class Bean {

    /**
     * sgc : false
     * sfy : false
     * qfy : false
     * lyricUser : {"id":29418062,"status":0,"demand":0,"userid":12907497,"nickname":"Simfre","uptime":1441503572343}
     * lrc : {"version":5,"lyric":"[by:简单de频率]\n[00:00.000] 做曲 : 张超\n[00:01.000] 做词 : 张超\n[00:22.600]苍茫的天涯是个人爱\n[00:26.280]绵绵的青山脚下花正开\n[00:30.130]什么样的节奏是最呀最摇摆\n[00:33.880]什么样的歌声才是最开怀\n[00:37.750]弯弯的河水从天上来\n[00:41.310]流向那万紫千红一片海\n[00:45.330]火辣辣的歌谣是咱们的期待\n[00:48.880]一路边走边唱才是最自在\n[00:52.630]咱们要唱就要唱得最痛快\n[00:56.610]你是我天边最美的云彩\n[01:00.280]让我用心把你留下来(留下来)\n[01:04.340]悠悠的唱着最炫的民族风\n[01:07.840]让爱卷走全部的尘埃\n[01:10.470](我知道)你是我心中最美的云彩\n[01:15.380]斟满美酒让你留下来(留下来)\n[01:19.380]永远都唱着最炫的民族风\n[01:22.760]是整片天空最美的姿态\n[01:26.700]哟啦啦呵啦呗\n[01:28.520]伊啦嗦啦呵啦呗呀\n[01:30.700]我听见你心中动人的天籁\n[01:34.260]登上天外云霄的舞台\n[01:37.530]\n[01:53.250]苍茫的天涯是个人爱\n[01:56.940]绵绵的青山脚下花正开\n[02:00.820]什么样的节奏是最呀最摇摆\n[02:04.570]什么样的歌声才是最开怀\n[02:08.440]弯弯的河水从天上来\n[02:12.000]流向那万紫千红一片海\n[02:15.810]火辣辣的歌谣是咱们的期待\n[02:19.620]一路边走边唱才是最自在\n[02:23.310]咱们要唱就要唱得最痛快\n[02:27.220]你是我天边最美的云彩\n[02:30.920]让我用心把你留下来(留下来)\n[02:34.920]悠悠的唱着最炫的民族风\n[02:38.410]让爱卷走全部的尘埃\n[02:41.410](我知道)你是我心中最美的云彩\n[02:46.210]斟满美酒让你留下来(留下来)\n[02:50.140]永远都唱着最炫的民族风\n[02:53.460]是整片天空最美的姿态\n[02:57.810]\n[03:18.290]你是我天边最美的云彩\n[03:21.910]让我用心把你留下来(留下来)\n[03:26.030]悠悠的唱着最炫的民族风\n[03:29.510]让爱卷走全部的尘埃\n[03:32.260](我知道)你是我心中最美的云彩\n[03:37.010]斟满美酒让你留下来(留下来)\n[03:41.070]永远都唱着最炫的民族风\n[03:44.570]是整片天空最美的姿态\n[03:48.990]\n[03:50.300]我听见你心中那动人的天籁\n[03:53.990]就忽如一晚上春风袭来满面桃花开\n[03:57.860]我忍不住去采 我忍不住去摘\n[04:01.620]我敞开胸怀为你等待\n[04:04.340]\n[04:05.840]你是我天边最美的云彩\n[04:09.280]让我用心把你留下来\n[04:13.010]悠悠的唱着最炫的民族风\n[04:16.750]让爱卷走全部的尘埃\n[04:19.500](我知道)你是我心中最美的云彩\n[04:24.250]斟满美酒让你留下来(留下来)\n[04:28.380]永远都唱着最炫的民族风\n[04:31.750]是整片天空最美的姿态\n[04:36.190]\n"}
     * klyric : {"version":0,"lyric":null}
     * tlyric : {"version":0,"lyric":null}
     * code : 200
     */

    private boolean sgc;
    private boolean sfy;
    private boolean qfy;
    private LyricUserBean lyricUser;
    private LrcBean lrc;
    private KlyricBean klyric;
    private TlyricBean tlyric;
    private int code;

    public boolean isSgc() {
        return sgc;
    }

    public void setSgc(boolean sgc) {
        this.sgc = sgc;
    }

    public boolean isSfy() {
        return sfy;
    }

    public void setSfy(boolean sfy) {
        this.sfy = sfy;
    }

    public boolean isQfy() {
        return qfy;
    }

    public void setQfy(boolean qfy) {
        this.qfy = qfy;
    }

    public LyricUserBean getLyricUser() {
        return lyricUser;
    }

    public void setLyricUser(LyricUserBean lyricUser) {
        this.lyricUser = lyricUser;
    }

    public LrcBean getLrc() {
        return lrc;
    }

    public void setLrc(LrcBean lrc) {
        this.lrc = lrc;
    }

    public KlyricBean getKlyric() {
        return klyric;
    }

    public void setKlyric(KlyricBean klyric) {
        this.klyric = klyric;
    }

    public TlyricBean getTlyric() {
        return tlyric;
    }

    public void setTlyric(TlyricBean tlyric) {
        this.tlyric = tlyric;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public static class LyricUserBean {
        /**
         * id : 29418062
         * status : 0
         * demand : 0
         * userid : 12907497
         * nickname : Simfre
         * uptime : 1441503572343
         */

        private int id;
        private int status;
        private int demand;
        private int userid;
        private String nickname;
        private long uptime;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public int getStatus() {
            return status;
        }

        public void setStatus(int status) {
            this.status = status;
        }

        public int getDemand() {
            return demand;
        }

        public void setDemand(int demand) {
            this.demand = demand;
        }

        public int getUserid() {
            return userid;
        }

        public void setUserid(int userid) {
            this.userid = userid;
        }

        public String getNickname() {
            return nickname;
        }

        public void setNickname(String nickname) {
            this.nickname = nickname;
        }

        public long getUptime() {
            return uptime;
        }

        public void setUptime(long uptime) {
            this.uptime = uptime;
        }
    }

    public static class LrcBean {
        /**
         * version : 5
         * lyric : [by:简单de频率]
         [00:00.000] 做曲 : 张超
         [00:01.000] 做词 : 张超
         [00:22.600]苍茫的天涯是个人爱
         [00:26.280]绵绵的青山脚下花正开
         [00:30.130]什么样的节奏是最呀最摇摆
         [00:33.880]什么样的歌声才是最开怀
         [00:37.750]弯弯的河水从天上来
         [00:41.310]流向那万紫千红一片海
         [00:45.330]火辣辣的歌谣是咱们的期待
         [00:48.880]一路边走边唱才是最自在
         [00:52.630]咱们要唱就要唱得最痛快
         [00:56.610]你是我天边最美的云彩
         [01:00.280]让我用心把你留下来(留下来)
         [01:04.340]悠悠的唱着最炫的民族风
         [01:07.840]让爱卷走全部的尘埃
         [01:10.470](我知道)你是我心中最美的云彩
         [01:15.380]斟满美酒让你留下来(留下来)
         [01:19.380]永远都唱着最炫的民族风
         [01:22.760]是整片天空最美的姿态
         [01:26.700]哟啦啦呵啦呗
         [01:28.520]伊啦嗦啦呵啦呗呀
         [01:30.700]我听见你心中动人的天籁
         [01:34.260]登上天外云霄的舞台
         [01:37.530]
         [01:53.250]苍茫的天涯是个人爱
         [01:56.940]绵绵的青山脚下花正开
         [02:00.820]什么样的节奏是最呀最摇摆
         [02:04.570]什么样的歌声才是最开怀
         [02:08.440]弯弯的河水从天上来
         [02:12.000]流向那万紫千红一片海
         [02:15.810]火辣辣的歌谣是咱们的期待
         [02:19.620]一路边走边唱才是最自在
         [02:23.310]咱们要唱就要唱得最痛快
         [02:27.220]你是我天边最美的云彩
         [02:30.920]让我用心把你留下来(留下来)
         [02:34.920]悠悠的唱着最炫的民族风
         [02:38.410]让爱卷走全部的尘埃
         [02:41.410](我知道)你是我心中最美的云彩
         [02:46.210]斟满美酒让你留下来(留下来)
         [02:50.140]永远都唱着最炫的民族风
         [02:53.460]是整片天空最美的姿态
         [02:57.810]
         [03:18.290]你是我天边最美的云彩
         [03:21.910]让我用心把你留下来(留下来)
         [03:26.030]悠悠的唱着最炫的民族风
         [03:29.510]让爱卷走全部的尘埃
         [03:32.260](我知道)你是我心中最美的云彩
         [03:37.010]斟满美酒让你留下来(留下来)
         [03:41.070]永远都唱着最炫的民族风
         [03:44.570]是整片天空最美的姿态
         [03:48.990]
         [03:50.300]我听见你心中那动人的天籁
         [03:53.990]就忽如一晚上春风袭来满面桃花开
         [03:57.860]我忍不住去采 我忍不住去摘
         [04:01.620]我敞开胸怀为你等待
         [04:04.340]
         [04:05.840]你是我天边最美的云彩
         [04:09.280]让我用心把你留下来
         [04:13.010]悠悠的唱着最炫的民族风
         [04:16.750]让爱卷走全部的尘埃
         [04:19.500](我知道)你是我心中最美的云彩
         [04:24.250]斟满美酒让你留下来(留下来)
         [04:28.380]永远都唱着最炫的民族风
         [04:31.750]是整片天空最美的姿态
         [04:36.190]

         */

        private int version;
        private String lyric;

        public int getVersion() {
            return version;
        }

        public void setVersion(int version) {
            this.version = version;
        }

        public String getLyric() {
            return lyric;
        }

        public void setLyric(String lyric) {
            this.lyric = lyric;
        }
    }

    public static class KlyricBean {
        /**
         * version : 0
         * lyric : null
         */

        private int version;
        private Object lyric;

        public int getVersion() {
            return version;
        }

        public void setVersion(int version) {
            this.version = version;
        }

        public Object getLyric() {
            return lyric;
        }

        public void setLyric(Object lyric) {
            this.lyric = lyric;
        }
    }

    public static class TlyricBean {
        /**
         * version : 0
         * lyric : null
         */

        private int version;
        private Object lyric;

        public int getVersion() {
            return version;
        }

        public void setVersion(int version) {
            this.version = version;
        }

        public Object getLyric() {
            return lyric;
        }

        public void setLyric(Object lyric) {
            this.lyric = lyric;
        }
    }
}
//实体类
package com.example.administrator.myapplication.day1704;

public class Music {
    private String text;
    private long start_time;

    @Override
    public String toString() {
        return "Music{" +
                "text='" + text + '\'' +
                ", start_time=" + start_time +
                '}';
    }

    public Music(String text, long start_time) {
        this.text = text;
        this.start_time = start_time;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public long getStart_time() {
        return start_time;
    }

    public void setStart_time(long start_time) {
        this.start_time = start_time;
    }
}

//效果图ui