1、简介
VideoView顾名思义就是播放视频的控件,使用VideoView是我们除了MediaPlayer + surfaceView之外播放视频的另一种写法,它继承自surfaceView,所以对UI的更新处理不太需要我们担心。
视频播放原理:
系统会首先确定视频的格式,然后得到视频的编码..然后对编码进行解码,得到一帧一帧的图像,最后在画布上进行迅速更新,显然需要在独立的线程中完成,这时就需要使用surfaceView了。surfaceView在这里就不说了,大家应该都知道是在另一个线程中去做UI更新操作。
2、xml配置
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.ht.videoplayer.MainActivity">
<VideoView
android:id="@+id/videoview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
android:id="@+id/button"
android:text="播放"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
在xml中我们只要确定VideoView的宽高即可,其它的我们多用代码来实现。
3、API方法
构造方法:
VideoView(Context context)
VideoView(Context context, AttributeSet attrs)
VideoView(Context context, AttributeSet attrs, int defStyle)
VideoView就跟我们自定义控件时的控件差不多,如果在代码中实例化一个View会调用第一个构造函数,如果在xml中定义会调用第二个构造函数,而第三个函数系统是不调用的,要由View(我们自定义的或系统预定义的View)显式调用,比如在这里我们在第二个构造函数中调用了第三个构造函数,并将style传给了第三个参数。
第三个参数的意义就如同它的名字所说的,是默认的Style,只是这里没有说清楚,这里的默认的Style是指它在当前Application或Activity所用的Theme中的默认Style。
//视频是否可以暂停。
boolean canPause()
//视频是否可以后退
boolean canSeekBackward()
//视频是否可以快进。
boolean canSeekForward()
//获取缓冲百分比
int getBufferPercentage()
//获取当前播放的位置
int getCurrentPosition()
//获取播放视频的总时间
int getDuration()
//判断视频是否处于播放状态
boolean isPlaying()
boolean onKeyDown (int keyCode, KeyEvent event)
KeyEvent.Callback.onKeyMultiple() 的默认实现。如果视图可用并可按, 当按下 KEYCODE_DPAD_CENTER 或 KEYCODE_ENTER 时执行视图的按下事件。
keyCode 表示按下的键的、在 KEYCODE_ENTER 中定义的键盘代码
event KeyEvent对象,定义了按钮动作
如果处理了事件,返回真。如果允许下一个事件接受器处理该事件,可以返回假。
boolean onTouchEvent (MotionEvent ev)
实现该方法来处理触屏事件。event 触屏事件,如果事件已经处理返回True,否则返回false。
boolean onTrackballEvent (MotionEvent ev)
实现这个方法去处理轨迹球的动作事件,轨迹球相对于上次事件移动的位置能用MotionEvent.getX() 和 MotionEvent.getY()函数取回。对应用户按下一次方向键, 他们通常作为一次移动处理(为了表现来自轨迹球的更小粒度的移动信息,他们返回小数)。ev 动作的事件。
//让视频播放暂停
void pause ()
int resolveAdjustedSize (int desiredSize, int measureSpec)
取得调整后的尺寸。如果measureSpec对象传入的模式是UNSPECIFIED那么返回的是desiredSize。如果measureSpec对象传入的模式是AT_MOST,返回的将是desiredSize和measureSpec对象的尺寸两者中最小的那个。如果measureSpec对象传入的模式是EXACTLY,那么返回的是measureSpec对象中的尺寸大小值。
关于specMode的几种模式,我在Android–自定义控件解析(二)这篇博客讲解onMeasure()方法的时候有介绍过,有兴趣的朋友可以看看。
//从暂停中恢复
void resume()
//跳转到指定的播放位置
void seekTo(int msec)
//设置媒体控制器,方便控制视频播放
void setMediaController(MediaController controller)
//媒体在播放完毕时的回调函数
void setOnCompletionListener(MediaPlayer.OnCompletionListener l)
//在设置或播放过程中发生错误时调用的回调函数。如果未指定回调函数, 或回调函数返回假,VideoView 会通知用户发生了错误。
//经常会碰到视频编码格式不支持的情况,若不想弹出提示框就返回true;
void setOnErrorListener(MediaPlayer.OnErrorListener l)
//在媒体文件加载完毕,可以播放时调用的回调函数
void setOnPreparedListener(MediaPlayer.OnPreparedListener l)
//设置视频文件的路径
void setVideoPath(String path)
//设置视频文件的统一资源标识符
void setVideoURI(Uri uri)
//开始播放视频文件
void start()
//停止回放视频文件
void stopPlayback()
//挂起视频文件的播放
void suspend()
通过suspend()函数,可使线程进入停滞状态。通过suspend()使线程进入停滞状态后,除非收到resume()消息,否则该线程不会变回可执行状态。
4、使用实例
在上面的API方法中我们可以看到有两种方法可以加载到视频文件,一种就是在本地路径中找文件,另一种是在网络上加载视频。要注意文件名小写字母,格式: 3gp,mp4等,flv的不一定支持。
分别用的方法是setVideoPath(String Path)和 setVideoURL(URL url),我们这篇博客只讲如何用VideoView播放视频,先看在本地如何加载视频。
可以看到我们已经把ht.mp4这个视频放到sdcard目录下了。当然要想访问sdcard,还需要权限,如果你的android系统是6.0或以上,你需要手动添加,不了解的朋友可以看我的博客Android–权限管理。
private VideoView mVideoView;
private Button play;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sdcardPermission();
play = (Button) findViewById(R.id.button);
String path = Environment.getExternalStorageDirectory().getPath() + File.separator + "ht.mp4";
mVideoView = (VideoView) findViewById(R.id.videoview);
mVideoView.setMediaController(new MediaController(this));
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
Toast.makeText(MainActivity.this, "播放完成", Toast.LENGTH_SHORT).show();
}
});
mVideoView.setVideoPath(path);
play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mVideoView.start();
}
});
}
可以看到没什么问题,我们再来网络上的,这里我用得不是Internet上的视频,而是用Tomcat搭建了个本地服务器,看这篇博客的朋友想要做事例也可以搭个本地服务器,不然就是在网络上找视频。
自然即使是本地服务器,你也是要添加网络权限的,不过INTERNET不是危险权限,所以不用手动添加。
而代码只要修改path为URI,执行方法换一下就OK啦。
Uri uri = Uri.parse("http://14.215.177.37:8080/video/ht.mp4");
mVideoView.setVideoURI(uri);
放在res/raw中的视频文件也可以使用setVideoURI(uri)
Uri rawUri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.ht);
mVideoView.setVideoURI(rawUri);
最后的结果自然也不会有变化。
结束语:本文仅用来学习记录,参考查阅。