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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
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
>
|
实现代码:VideoViewActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
|
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
1
2
3
4
5
6
7
8
9
10
11
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
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
>
|
实现代码:ControllerActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
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去完成。
原文出处:http://www.bdqn.cn/news/201311/12100.shtml