一、VideoView及其相关组件总结
在Android中,播放视频有2种方式,第一种方式是使用MediaPlayer结合SurfaceView来播放,通过MediaPlayer来控制视频的播放、暂停、进度等,而通过SurfaceView来显示视频内容;第二种方式是使用VideoView来播放,这个类其实也是继承了SurfaceView类,并且实现了MediaController.MediaPlayerController这个用于控制媒体播放的接口,另外在VideoView上还有一个用于对媒体播放进行控制的面板,包括快进、快退、播放、暂停按钮以及一个进度条。
使用VideoView播放视频的好处是简单因为它已经帮我们实现了SurfaceView以及控制方法,开发过程中只需直接拿来使用就可以了,但它的缺点是不够灵活。而是用MediaPlayer结合SurfaceView来播放视频的话,好处是可以更灵活的对其进行自定义,缺点是难度较大。
android.widget.VideoView
(1)JAVA Framework层,应用程序进来之后到VideoView,再经过Surface;
(2)Native Framework层,先到SurfaceFlinger,然后到OverlayHal,同时借助了PVPlayer;
(3)Driver层,利用Main framebuffer和Video Plane进行播放;
1.1通过VideoView播放视频步骤:
1、在界面布局文件中定义VideoView组件,或在程序中创建VideoView组件
2、在Activity中获取布局文件中的组件并设置相应的监听;
3、调用VideoView的如下两个方法来加载指定的视频:
(1)setVideoPath(String path):加载path文件代表的视频
(2)setVideoURI(URI uri):加载uri所对应的视频
在使用setVideoURI(URI uri)方法之前要设置网络视频路径
4、调用VideoView的start()、pause()、resume()、stopPlayback()方法控制视频的播放(开始、暂停、继续、停止),VideoView的getDuration()可以返回视频的长度,可以结合VideoView的resume()方法进行记忆播放和缓存播放。
例如 播放raw中的视频:
VideoView videoView = findViewById(R.id.videoView);
MediaController mediaController = new MediaController(this);
mediaController.setPrevNextListeners(this, this);
videoView.setMediaController(mediaController);
/*Uri uri =Uri.parse("android.resource://"+ this.getPackageName() + "/"+ R.raw.audio_6);
videoView.setVideoURI(uri);*/
videoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" +R.raw.video_6));
//videoView.setVideoPath(new File(getExternalFilesDir(""), "a.mp4").getAbsolutePath());
videoView.start();
播放指定视频源文件
{
mediaPlayer = new MediaPlayer();
//设置准备监听
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnCompletionListener(this);
try {
//指定视频源
mediaPlayer.setDataSource(new File(getExternalFilesDir(""), "a.mp4").getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.setSurface(new Surface(textureView.getSurfaceTexture()));
mediaPlayer.prepareAsync(); //同步
}
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
}
@Override
public void onCompletion(MediaPlayer mp) {
btn_opt.setText("开始");
mediaPlayer.release();
}
1.2 VideoView常用方法
Android VideoView类为我们提供了十分方便的视频播放API,其主要方法有:
方法名称
说明
- void start() 开始播放
- void stopPlayback() 停止播放
- void pause() 暂停
- void resume() 重新播放
- void seekTo(int msec) 从第几毫秒开始播放
- int getCurrentPosition() 获取当前播放位置
- int getDuration() 获取当前视频总长度
- boolean isPlaying() 当前VideoView是否在播放视频
- void setVideoPath(String path) 以文件路径的方式设置VideoView播放的视频源
- void setVideoURI(URI uri) 以Uri的方式设置视频源,可以是网络Uri或本地Uri
- setMediaCotroller(MediaController controller) 设置MediaController控制器
- setOnCompletionListener(MediaPlayer.onCompletionListener l) 监听播放完成的事件
- setOnErrorListener(MediaPlayer.OnErrorListener l) 监听播放发生错误时候的事件
- setOnPreparedListener(MediaPlayer.OnPreparedListener l) 监听视频装载完成的事件
1.3 Media Controller类
Media Controller类为我们提供了一个悬浮的操作栏,包含了播放,暂停,快进,快退,上一个,下一个等功能键。还有拖动进度条至某一处也可以实现。在使用前VideoView和MeidaController需要相互指定控件。
Mdedia Controller类包含的内置方法有:
方法名称
说明
- boolean isShowing() 当前悬浮控制栏是否显示。
- void setMediaPlayer(MediaController.MediaPlayerControl player) 设置控制的组件
- void hide() 隐藏MeidaController
- void show() 显示MeidaController
- void show(int timeout) 设置MidiaController显示的时间,以毫秒计算。如果设置为0则一直到调用hide()方法隐藏
- void setPrevNextListeners(View.OnClickListenernext,View.OnClickListener prev) 设置上一个视频下一个视频的切换事件
- 默认情况下,Media Controller悬浮显示3s后隐藏,触摸响应的VideoView呼出。默认上一个,下一个按钮隐藏。
1.4 视频格式
1.4.1 Android支持的视频编码格式
1.4.2 VideoView支持的影片格式
在实际测试中过程中,发现了一些由VideoView发出的Toast警告,内容写着不支持影片格式,以致无法播放。VideoView仅能播放progressive streamable(渐进式流)的影片,一般的mp4或3gp若不采用progressive streamable模式转文件的影片,是无法被VideoView通过网络播放的,但假如存放在local端(如储存卡)则不在此限。
1.5 VideoView的监听处理
开发过程中使用的VideoView监听一共有3个:setOnCompletionListener(MediaPlayer.onCompletionListener l)、setOnErrorListener(MediaPlayer.OnErrorListener l)、setOnPreparedListener(MediaPlayer.OnPreparedListener l)
1.5.1 setOnCompletionListener(MediaPlayer.onCompletionListener l)
setOnCompletionListener(MediaPlayer.onCompletionListener l)
用于监听视频播放完成后的事件
1.5.2 setOnErrorListener(MediaPlayer.OnErrorListener l)
setOnErrorListener(MediaPlayer.OnErrorListener l)
用于监听VideoView在使用过程中出现的各种错误。
错误常数:
- MEDIA_ERROR_IO 文件不存在或错误,或网络不可访问错误 值: -1004 (0xfffffc14)
- MEDIA_ERROR_MALFORMED 流不符合有关标准或文件的编码规范 值: -1007 (0xfffffc11)
- MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK
视频流及其容器不适用于连续播放视频的指标(例如:MOOV原子)不在文件的开始. 值: 200 (0x000000c8) - MEDIA_ERROR_SERVER_DIED 媒体服务器挂掉了。此时,程序必须释放MediaPlayer 对象,并重新new
一个新的。 值: 100 (0x00000064) - MEDIA_ERROR_TIMED_OUT 一些操作使用了过长的时间,也就是超时了,通常是超过了3-5秒 值: -110 (0xffffff92)
- MEDIA_ERROR_UNKNOWN 未知错误 值: 1 (0x00000001)
- MEDIA_ERROR_UNSUPPORTED 比特流符合相关编码标准或文件的规格,但媒体框架不支持此功能 值: -1010
(0xfffffc0e) - what int: 标记的错误类型: MEDIA_ERROR_UNKNOWN MEDIA_ERROR_SERVER_DIED
- extra int: 标记的错误类型. MEDIA_ERROR_IO MEDIA_ERROR_MALFORMED
MEDIA_ERROR_UNSUPPORTED MEDIA_ERROR_TIMED_OUT MEDIA_ERROR_SYSTEM
(-2147483648) - low-level system error.
1.5.3 setOnPreparedListener(MediaPlayer.OnPreparedListener l)
setOnPreparedListener(MediaPlayer.OnPreparedListener l)
用于监听视频装在完成后的事件
二、视频旋转
在网上查询了众多的关于屏幕旋转的方法。总结起来可以分为4种。在介绍之前要先了解默认情况下Android屏幕旋转机制(当然是在手机本身屏幕旋转功能开启的时候才能实现,自己在开发过程中一直发现开发视频不能随着手机一起旋转,弄了几个小时才发现是自己Android本身自带的旋转按钮没有开启):
默认情况下,当用户的重力感应器打开后,屏幕旋转方向会导致当前activity发生onDestory->onCreate,这样会重新构造当前activity和界面布局,如果是在Camera界面,则表现为卡顿或者黑屏一段时间。如果是在横竖屏UI设计方面,那么想很好的支持屏幕旋转,则建议在res中建立layout-land和layport两个文件夹,把横屏和竖屏的文件分别放入对应的layout文件夹中。
2.1 AndroidMainfest.xml设置
如果单单想设置横屏或者竖屏,那么只需添加横竖屏代码:
优点:即使屏幕旋转,Actiity也不会重新onCreate。
缺点:屏幕只有一个方向
2.2 代码动态设置
如果需要动态改变横竖屏设置,只要在代码中调用setRequestedOrientation()函数:
优点:可以随意动态设置,满足人们为改变横竖屏的要求,同时满足横竖屏UI不同的设计需求
缺点:如果改变设置,那么Activity会被销毁,重新构建,即重新onCreate;
2.3 重写onCongigurationChanged
使用此方法可以避免旋转屏幕时Activity被不断的onCreate情况(这种情况下往往造成屏幕切换时的卡顿)。
首先,在AndroidMainfest.xml中添加configChanges:
注意:keyboardHidden表示键盘辅助功能隐藏,如果你的开发API等级等于或高于13,还需要设置screenSize,因为screenSize会在屏幕旋转时改变
然后,在Activity中重写onConfigurationChanged方法,这个方法将会在屏幕旋转变化时,进行监听处理:
优点:可以随时监听屏幕旋转变化,并对应做出相应操作
缺点:它只能一次旋转90°,如果一下子旋转180°,onConfigurationChanged函数不会被调用。
2.4 结合OrientationEventListener,自定义旋转监听设置
这种方法由于自定义回掉接口暂时不明白,在这里暂不总结。
可以参考网站:http://www.jb51.net/article/64735.htm
三、误按返回操作
为了防止用户误按返回键而退出播放,可以在程序中重写onKeyDown方法。在这个方法中来处理用户点击返回键的动作:例如只有用户在短时间内点击两次返回键才真正退出播放。
四、设置手机全屏
4.1 最常用的设置全屏方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置无标题
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 设置全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
}
使用上述方法注意:requestWindowFeature()方法一定要在setContentView()前面,否则会报错;
4.2 AndroidManifest中配置
利用Android提供的内置的Theme就可以了。
五、设置屏幕显示方向
当不定义横竖屏的情况下,这个app会随着手机的转向设置变化而变化,而我们对于横竖屏切换肯定要做相应的事情,可以如下方法去做:
if (getResources().getConfiguration().orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
// 处理横屏下要做的事
} else {
// 处理竖屏下要做的事情
}
在这个视频软件中我要做到一个点击按钮让手机旋转的功能,就是用到了上面的代码:
六、取消全屏的方法
getWindow().clearFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN);
七、Android系统自带样式
android:theme=“@android:style/Theme.Dialog” 将一个Activity显示为能话框模式
android:theme=“@android:style/Theme.NoTitleBar” 不显示应用程序标题栏
android:theme=“@android:style/Theme.NoTitleBar.Fullscreen” 不显示应用程序标题栏,并全屏
android:theme=“Theme.Light” 背景为白色
android:theme=“Theme.Light.NoTitleBar” 白色背景并无标题栏
android:theme=“Theme.Light.NoTitleBar.Fullscreen” 白色背景,无标题栏,全屏
android:theme=“Theme.Black” 背景黑色
android:theme=“Theme.Black.NoTitleBar” 黑色背景并无标题栏
android:theme=“Theme.Black.NoTitleBar.Fullscreen” 黑色背景,无标题栏,全屏
android:theme=“Theme.Wallpaper” 用系统桌面为应用程序背景
android:theme=“Theme.Wallpaper.NoTitleBar” 用系统桌面为应用程序背景,且无标题栏
android:theme=“Theme.Wallpaper.NoTitleBar.Fullscreen” 用系统桌面为应用程序背景,无标题栏,全屏
android:theme=“Translucent” 透明背景
android:theme=“Theme.Translucent.NoTitleBar” 透明背景并无标题
android:theme=“Theme.Translucent.NoTitleBar.Fullscreen” 透明背景并无标题,全屏
android:theme=“Theme.Panel” 面板风格显示
android:theme=“Theme.Light.Panel” 平板风格显示