VideoView
VideoView,用于播放一段视频媒体,它继承了SurfaceView,位于"android.widget.VideoView",是一个视频控件。
既然是播放一段视频,那么不可避免的要涉及到一些开始、暂停、停止等操作,VideoView也为开发人员提供了对应的方法,这里简单介绍一些常用的:
int getCurrentPosition():获取当前播放的位置。
int getDuration():获取当前播放视频的总长度。
isPlaying():当前VideoView是否在播放视频。
void pause():暂停
void seekTo(int msec):从第几毫秒开始播放。
void resume():重新播放。
void setVideoPath(String path):以文件路径的方式设置VideoView播放的视频源。
void setVideoURI(Uri uri):以Uri的方式设置VideoView播放的视频源,可以是网络Uri或本地Uri。
void start():开始播放。
void stopPlayback():停止播放。
setMediaController(MediaController controller):设置MediaController控制器。
setOnCompletionListener(MediaPlayer.onCompletionListener l):监听播放完成的事件。
setOnErrorListener(MediaPlayer.OnErrorListener l):监听播放发生错误时候的事件。
setOnPreparedListener(MediaPlayer.OnPreparedListener l)::监听视频装载完成的事件。
上面的一些方法通过方法名就可以了解用途。和MediaPlayer配合SurfaceView播放视频不同,VideoView播放之前无需编码装载视频,它会在start()开始播放的时候自动装载视频。并且VideoView在使用完之后,无需编码回收资源。
VideoView简单的Demo
VideoView其实没有什么难点,通过它自带的API方法,即可完成一段视频的播放,无非就是注意它方法的调用时机即可。下面通过一个简单的Demo,演示VideoView如何播放一段SD卡上的视频文件。在Demo中提供了四个Button,分别表示播放、暂停、重播、停止,并配合进度条显示。代码注释比较完整,细节部分这里不再累述。
布局代码:activity_videoview.xml
<?
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:orientation
=
"vertical"
>
<
EditText
android:id
=
"@+id/et_path"
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
android:text
=
"/sdcard/ykzzldx.mp4"
/>
<
SeekBar
android:id
=
"@+id/seekBar"
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
/>
<
LinearLayout
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:orientation
=
"horizontal"
>
<
Button
android:id
=
"@+id/btn_play"
android:layout_width
=
"0dip"
android:layout_height
=
"wrap_content"
android:layout_weight
=
"1"
android:text
=
"播放"
/>
<
Button
android:id
=
"@+id/btn_pause"
android:layout_width
=
"0dip"
android:layout_height
=
"wrap_content"
android:layout_weight
=
"1"
android:text
=
"暂停"
/>
<
Button
android:id
=
"@+id/btn_replay"
android:layout_width
=
"0dip"
android:layout_height
=
"wrap_content"
android:layout_weight
=
"1"
android:text
=
"重播"
/>
<
Button
android:id
=
"@+id/btn_stop"
android:layout_width
=
"0dip"
android:layout_height
=
"wrap_content"
android:layout_weight
=
"1"
android:text
=
"停止"
/>
</
LinearLayout
>
<
VideoView
android:id
=
"@+id/vv_videoview"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
/>
</
LinearLayout
>
package
cn.bgxt.videoviewdemo;
import
java.io.File;
import
android.app.Activity;
import
android.media.MediaPlayer;
import
android.media.MediaPlayer.OnCompletionListener;
import
android.media.MediaPlayer.OnErrorListener;
import
android.os.Bundle;
import
android.util.Log;
import
android.view.View;
import
android.widget.Button;
import
android.widget.EditText;
import
android.widget.SeekBar;
import
android.widget.Toast;
import
android.widget.VideoView;
import
android.widget.SeekBar.OnSeekBarChangeListener;
public
class
VideoViewActivity
extends
Activity {
private
final
String TAG =
"main"
;
private
EditText et_path;
private
Button btn_play, btn_pause, btn_replay, btn_stop;
private
SeekBar seekBar;
private
VideoView vv_video;
private
boolean
isPlaying;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_videoview);
seekBar = (SeekBar) findViewById(R.id.seekBar);
et_path = (EditText) findViewById(R.id.et_path);
vv_video = (VideoView) findViewById(R.id.vv_videoview);
btn_play = (Button) findViewById(R.id.btn_play);
btn_pause = (Button) findViewById(R.id.btn_pause);
btn_replay = (Button) findViewById(R.id.btn_replay);
btn_stop = (Button) findViewById(R.id.btn_stop);
btn_play.setOnClickListener(click);
btn_pause.setOnClickListener(click);
btn_replay.setOnClickListener(click);
btn_stop.setOnClickListener(click);
// 为进度条添加进度更改事件
seekBar.setOnSeekBarChangeListener(change);
}
private
OnSeekBarChangeListener change =
new
OnSeekBarChangeListener() {
@Override
public
void
onStopTrackingTouch(SeekBar seekBar) {
// 当进度条停止修改的时候触发
// 取得当前进度条的刻度
int
progress = seekBar.getProgress();
if
(vv_video !=
null
&& vv_video.isPlaying()) {
// 设置当前播放的位置
vv_video.seekTo(progress);
}
}
@Override
public
void
onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public
void
onProgressChanged(SeekBar seekBar,
int
progress,
boolean
fromUser) {
}
};
private
View.OnClickListener click =
new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
switch
(v.getId()) {
case
R.id.btn_play:
play(
0
);
break
;
case
R.id.btn_pause:
pause();
break
;
case
R.id.btn_replay:
replay();
break
;
case
R.id.btn_stop:
stop();
break
;
default
:
break
;
}
}
};
protected
void
play(
int
msec) {
Log.i(TAG,
" 获取视频文件地址"
);
String path = et_path.getText().toString().trim();
File file =
new
File(path);
if
(!file.exists()) {
Toast.makeText(
this
,
"视频文件路径错误"
,
0
).show();
return
;
}
Log.i(TAG,
"指定视频源路径"
);
vv_video.setVideoPath(file.getAbsolutePath());
Log.i(TAG,
"开始播放"
);
vv_video.start();
// 按照初始位置播放
vv_video.seekTo(msec);
// 设置进度条的最大进度为视频流的最大播放时长
seekBar.setMax(vv_video.getDuration());
// 开始线程,更新进度条的刻度
new
Thread() {
@Override
public
void
run() {
try
{
isPlaying =
true
;
while
(isPlaying) {
// 如果正在播放,没0.5.毫秒更新一次进度条
int
current = vv_video.getCurrentPosition();
seekBar.setProgress(current);
sleep(
500
);
}
}
catch
(Exception e) {
e.printStackTrace();
}
}
}.start();
// 播放之后设置播放按钮不可用
btn_play.setEnabled(
false
);
vv_video.setOnCompletionListener(
new
OnCompletionListener() {
@Override
public
void
onCompletion(MediaPlayer mp) {
// 在播放完毕被回调
btn_play.setEnabled(
true
);
}
});
vv_video.setOnErrorListener(
new
OnErrorListener() {
@Override
public
boolean
onError(MediaPlayer mp,
int
what,
int
extra) {
// 发生错误重新播放
play(
0
);
isPlaying =
false
;
return
false
;
}
});
}
/**
* 重新开始播放
*/
protected
void
replay() {
if
(vv_video !=
null
&& vv_video.isPlaying()) {
vv_video.seekTo(
0
);
Toast.makeText(
this
,
"重新播放"
,
0
).show();
btn_pause.setText(
"暂停"
);
return
;
}
isPlaying =
false
;
play(
0
);
}
/**
* 暂停或继续
*/
protected
void
pause() {
if
(btn_pause.getText().toString().trim().equals(
"继续"
)) {
btn_pause.setText(
"暂停"
);
vv_video.start();
Toast.makeText(
this
,
"继续播放"
,
0
).show();
return
;
}
if
(vv_video !=
null
&& vv_video.isPlaying()) {
vv_video.pause();
btn_pause.setText(
"继续"
);
Toast.makeText(
this
,
"暂停播放"
,
0
).show();
}
}
/*
* 停止播放
*/
protected
void
stop() {
if
(vv_video !=
null
&& vv_video.isPlaying()) {
vv_video.stopPlayback();
btn_play.setEnabled(
true
);
isPlaying =
false
;
}
}
}
效果展示:
MediaController
提到VideoView不得不再说一些MediaController。虽然VideoView为我们提供了方便的API用于播放、暂停、停止等操作,但是还是需要我们编码完成,但是如果使用了MediaController的话,那么这些操作都可以省去。
MediaController可以用于配合VideoView播放一段视频,它为VideoView提供一个悬浮的操作栏,在操作栏中可以对 VideoView播放的视频进行控制,默认情况下,会悬浮显示三秒。它通过MediaController.setMediaPlayer()方法进行指定需要控制的VideoView,但是仅仅这样是不够的,MediaController的控制需要类似于双向控制,MediaController指定控制的VideoView,VideoView还需要指定那个MediaController来控制它,这需要使用 VideoView.setMediaController()方法。
下面介绍一下MediaController的一些常用方法;
boolean isShowing():当前悬浮控制栏是否显示。
void setMediaPlayer(MediaController.MediaPlayerControl player):设置控制的组件。
void setPrevNextListeners(View.OnClickListener next,View.OnClickListener prev):设置上一个视频、下一个视频的切换事件。
通过上面的方法可以看出setMediaPlayer()并非指定的是一个VideoView,而是一个MediaPlayerControl 接口,MediaPlayerControl接口内部定义了一些播放相关的播放、暂停、停止等操作,而VideoView实现了 MediaPlayerControl。
默认情况下,如果不通过setPrevNextListeners()设置切换视频的监听器,MediaController是不会显示这两个按钮的。
MediaController简单的Demo
上面已经讲过MediaController的一些内容,下面通过一个简单的Demo来演示一下MediaController控制VideoView播放视频。
布局代码:activity_controller.xml
<?
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:orientation
=
"vertical"
>
<
VideoView
android:id
=
"@+id/vv_video"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
/>
</
LinearLayout
>
package
cn.bgxt.videoviewdemo;
import
java.io.File;
import
android.app.Activity;
import
android.os.Bundle;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.MediaController;
import
android.widget.Toast;
import
android.widget.VideoView;
public
class
ControllerActivity
extends
Activity {
private
VideoView vv_video;
private
MediaController mController;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_controller);
vv_video=(VideoView) findViewById(R.id.vv_video);
// 实例化MediaController
mController=
new
MediaController(
this
);
File file=
new
File(
"/sdcard/ykzzldx.mp4"
);
if
(file.exists()){
// 设置播放视频源的路径
vv_video.setVideoPath(file.getAbsolutePath());
// 为VideoView指定MediaController
vv_video.setMediaController(mController);
// 为MediaController指定控制的VideoView
mController.setMediaPlayer(vv_video);
// 增加监听上一个和下一个的切换事件,默认这两个按钮是不显示的
mController.setPrevNextListeners(
new
OnClickListener() {
@Override
public
void
onClick(View v) {
Toast.makeText(ControllerActivity.
this
,
"下一个"
,
0
).show();
}
},
new
OnClickListener() {
@Override
public
void
onClick(View v) {
Toast.makeText(ControllerActivity.
this
,
"上一个"
,
0
).show();
}
});
}
}
}
效果展示:
从上面展示的效果可以看出,MediaController不光为我们增加了控制栏来控制播放、暂停、快进、快退、切换上一视频、切换下一视频,还增加了进度条显示。
总结
本篇博客就讲解了VideoView和MediaController的内容。虽然使用MediaController非常的方便,基本上所有的操作都帮我们封装好了,但是封装即表示不够灵活,必须按照既定的规则去实现。所以一般专业的视频播放应用,还是会使用SurfaceView去完成。