添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
实战第12篇:SurfaceView实现视频播放的展示

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天, 点击查看活动详情

今天是8月12号,是我写原创专栏 《java转android》 跟随8月更文活动的第12天。没有了推荐首页,也没有了大家不看好的评论,我反而清净了。

本次实战项目,开发一个视频播放器,可对本地或者网络视频进行播放,支持暂停、继续。

一、所需知识

主要涉及两点知识:1、 MediaPlayer 处理视频数据;2、 SurfaceView 呈现视频画面。

1.1 MediaPlayer 媒体播放器

我们采用 MediaPlayer 进行视频数据的解析。

关于 MediaPlayer 的介绍,虽然我很想再复制一遍,但是掘金不提倡。掘金作为一个高质量的内容平台,拒绝重复数据,所以大家想要了解可以去昨天的《 第11篇:MediaPlayer实现音频播放 》查看。一些问题的答案,可能就在那里。

为了便于理解本期的内容,提示大家重点看3处知识:

  • MediaPlayer的创建。
  • 加载多媒体文件的方式。
  • 控制媒体状态的常用方法。
  • 好了,假设 MediaPlayer 你已经完全掌握了。

    1.2 SurfaceView 表面视图

    SurfaceView ……又遇到一个不好翻译的类。

    View 我们都不陌生,比如 Button TextView ImageView 都是 View 。但是,这个 View 是静态的,你的按钮不怎么更新吧,图片也是赋值一次基本不怎么变。有需要更新时,我们给它 set 新数据就可以了。

    但是,还有一类场景很难搞定,那就是: 地图 视频 游戏

    这些都是高频率刷新的,一秒钟几十帧。这时,传统的 View 就有心无力了,如果资源都放在刷新上,那么UI主线程会很卡。

    所以 SurfaceView 就出现了,它提供一个在内存中的临时缓冲区,叫做表面视图,我觉得叫它 表层 视图更贴切。

    下面,我们来说它的用法。

    我们还是可以像用普通 View 一样通过 xml 定义 SurfaceView

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="240dp"
    

    但是,到逻辑代码面,我们没法直接操作SurfaceView,需要通过SurfaceHolder来对它进行操作。

    SurfaceView surfaceView = findViewById(R.id.surfaceView);
    SurfaceHolder surfaceHolder = surfaceView.getHolder();
    surfaceHolder.addCallback(new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // SurfaceView 创建完成时,你要对它做什么
        …… ……            
    

    二、实战开发

    再来回顾一下,我们要做的这个视频播放器。

    2.1 布局

    我们来理一下思路,界面的组成是一个SurfaceView加上2个按钮,SurfaceView用于展示视频的画面。

    下面是布局文件activity_main.xml的代码。

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
        <SurfaceView
            android:id="@+id/sfvShow"
            android:layout_width="match_parent"
            android:layout_height="240dp"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        <Button
            android:id="@+id/btnStart"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="24dp"
            android:onClick="start"
            android:text="开始"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/sfvShow" />
        <Button
            android:id="@+id/btnStop"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="8dp"
            android:onClick="pause"
            android:text="暂停"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="@+id/btnStart" />
    </android.support.constraint.ConstraintLayout>
    

    我们看到SurfaceView就是普通的定义方式。

    2.2 逻辑

    在Activity里,如何实现MediaPlayer和SurfaceView的结合呢?来,看整体代码!

    public class MainActivity extends Activity { private MediaPlayer mediaPlayer = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mediaPlayer = MediaPlayer.create(MainActivity.this, R.raw.video_test); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); SurfaceView sfvShow = findViewById(R.id.sfvShow); //初始化SurfaceHolder类,SurfaceView的控制器 final SurfaceHolder surfaceHolder = sfvShow.getHolder(); surfaceHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { //设置视频显示在SurfaceView上 mediaPlayer.setDisplay(surfaceHolder); @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} @Override public void surfaceDestroyed(SurfaceHolder holder) {} public void start(View view) { mediaPlayer.start(); public void pause(View view) { mediaPlayer.pause();

    首先是创建MediaPlayer,然后加载raw文件夹下的视频文件,我们依然采用上一节中的工厂模式,实现创建加载一条龙。

    然后,建立SurfaceView,通过SurfaceView的getHolder()方法获取到SurfaceHolder

    下一步,给SurfaceHolder设置回调方法,此方法包含了整个SurfaceView的创建、变化、销毁的周期。也就说,它创建时,你可以拿到它的实例。它销毁时,你也能得到通知,然后做一些事情。那么,我们在它创建时,我们调用了mediaPlayer.setDisplay(surfaceHolder),把播放器的显示权交给surfaceHolder,让它负责视频画面的承载。

    点击播放和暂停,正常调用MediaPlayer的start()pause()方法就可以。

    写程序要严谨,在Activity的销毁方法里,要加上一段收尾的处理。

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
        mediaPlayer.release();
    

    如果程序要退出,记得把视频关掉,把播放器销毁。不然会出现,程序关了,视频的声音还在播放,你也关不掉,挺吓人的。

    以上代码,注意把视频文件放到raw文件下,并通过R.raw.[xx]正确引用。点击运行,可实现视频的播放和暂停。如果是要播放网络视频,调用setDataSource("http://juejin.cn/ok.mp4")设置一个视频源url就可以了,上一篇也有相关知识点的讲解

    我们可以做一款自己的视频播放器,只允许看一遍,不允许回退,每天只允许看10分钟,甚至只限于八点到九点之间才能看。

    总之,规则由自己定,这就是开发的乐趣。

    我是TF男孩,关注我的掘金专栏《Java转Android》。日读800字,30天可入门安卓开发。