携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天, 点击查看活动详情
今天是8月12号,是我写原创专栏 《java转android》 跟随8月更文活动的第12天。没有了推荐首页,也没有了大家不看好的评论,我反而清净了。
本次实战项目,开发一个视频播放器,可对本地或者网络视频进行播放,支持暂停、继续。
一、所需知识
主要涉及两点知识:1、
MediaPlayer
处理视频数据;2、
SurfaceView
呈现视频画面。
1.1 MediaPlayer 媒体播放器
我们采用
MediaPlayer
进行视频数据的解析。
关于
MediaPlayer
的介绍,虽然我很想再复制一遍,但是掘金不提倡。掘金作为一个高质量的内容平台,拒绝重复数据,所以大家想要了解可以去昨天的《
第11篇:MediaPlayer实现音频播放
》查看。一些问题的答案,可能就在那里。
为了便于理解本期的内容,提示大家重点看3处知识:
好了,假设
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天可入门安卓开发。