您的位置:首页 > 移动开发 > Android开发

关于VideoView无法监听视频播放时缓冲或者卡顿状态的解决办法

2013-12-03 16:45 826 查看
首先在android使用系统自带播放器有三种实现方式:

1、使用其自带的播放器。指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型。

 

2、使用VideoView来播放。在布局文件中使用VideoView结合MediaController来实现对其控制。

 

3、使用MediaPlayer类和SurfaceView来实现。这种方式最灵活,也最复杂。

对于第一种和第三种都有办法实现对正在播放的视频进行缓冲监听,请自行谷歌。而对于第二种要实现对缓冲状态进行监听,复杂的方法就是重写VideoView,去继承写MediaPlayer中的方法,从而通过第3种方式实现监听。

对于只简单的使用了VideoView来播放视频的应用有没有其他简便的方法来实现对缓冲状态的监听呢?我们先简单的看下VideoView的API。

公共方法

public boolean canPause ()

(译者注:判断是否能够暂停播放视频)

 

public boolean canSeekBackward ()

(译者注:判断是否能够倒退)

 

public boolean canSeekForward ()

(译者注:判断是否能够快进)

 

public int getBufferPercentage ()

(译者注:获得缓冲区的百分比)

 

public int getCurrentPosition ()

(译者注:获得当前的位置)

 

public int getDuration ()

(译者注:获得所播放视频的总时间)

 

public boolean isPlaying ()

(译者注:判断是否正在播放视频)

 

public boolean onKeyDown (int keyCode, KeyEvent event)

KeyEvent.Callback.onKeyMultiple() 的默认实现。如果视图可用并可按, 当按下 KEYCODE_DPAD_CENTER 或 KEYCODE_ENTER 时执行视图的按下事件。

参数

keyCode   表示按下的键的、在 KEYCODE_ENTER 中定义的键盘代码

event        KeyEvent 对象,定义了按钮动作

返回值

如果处理了事件,返回真。如果允许下一个事件接受器处理该事件,可以返回假

 

public boolean onTouchEvent (MotionEvent ev)

实现该方法来处理触屏事件。

参数

event        触屏事件

返回值

如果事件已经处理返回True,否则返回false。

 

public boolean onTrackballEvent (MotionEvent ev)

实现这个方法去处理轨迹球的动作事件,轨迹球相对于上次事件移动的位置能用MotionEvent.getX() 和 MotionEvent.getY()函数取回。对应用户按下一次方向键, 他们通常作为一次移动处理(为了表现来自轨迹球的更小粒度的移动信息,他们返回小数)。

参数

ev     动作的事件

 

public void pause ()

(译者注:使得播放暂停)

 

public int resolveAdjustedSize (int desiredSize, int measureSpec)

(译者注:取得调整后的尺寸。如果measureSpec对象传入的模式是UNSPECIFIED那么返回的是desiredSize。如果measureSpec对象传入的模式是AT_MOST,返回的将是desiredSize和measureSpec对象的尺寸两者中最小的那个。如果measureSpec对象传入的模式是EXACTLY,那么返回的是measureSpec对象中的尺寸大小值。

关于MeasureSpec类的额外说明:MeasureSpec是一个android.view.View的内部类。它封装了从父类传送到子类的布局要求信息。每个MeasureSpec对象描述了控件的高度或者宽度。MeasureSpec对象是由尺寸和模式组成的,有3个模式:UNSPECIFIED、EXACTLY、AT_MOST,这个对象由MeasureSpec.makeMeasureSpec()函数创建。)

 

public void resume ()

(译者注:恢复挂起的播放器)

 

public void seekTo (int msec)

(译者注:设置播放位置)

 

public void setMediaController (MediaController controller)

(译者注:设置媒体控制器)

        

public void setOnCompletionListener (MediaPlayer.OnCompletionListener l)

注册在媒体文件播放完毕时调用的回调函数。

参数

l        要执行的回调函数

 

public void setOnErrorListener (MediaPlayer.OnErrorListener l)

注册在设置或播放过程中发生错误时调用的回调函数。如果未指定回调函数, 或回调函数返回假,VideoView 会通知用户发生了错误。

参数

l        要执行的回调函数

 

public void setOnPreparedListener (MediaPlayer.OnPreparedListener l)

注册在媒体文件加载完毕,可以播放时调用的回调函数。

参数

l        要执行的回调函数

        

public void setVideoPath (String path)

(译者注:设置视频文件的路径名)

 

public void setVideoURI (Uri uri)

(译者注:设置视频文件的统一资源标识符)

 

public void start ()

(译者注:开始播放视频文件)

 

public void stopPlayback ()

(译者注:停止回放视频文件)

 

public void suspend ()

(译者注:挂起视频文件的播放)

看完发现VideoView的方法的确比其他的少了很多。但是我们看到了

public int getBufferPercentage ()

(译者注:获得缓冲区的百分比)

 

public int getCurrentPosition ()

(译者注:获得当前的位置)
这2个方法。最开始的想法是通过比较当前位置和缓冲区的百分比是否相等,来判断是否卡顿或者是出于缓冲状态。但是后来在http://stackoverflow.com/questions/7867233/detect-if-a-videoview-is-buffering 
这里看到了一个解决方法。

final Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
int duration = videoView.getCurrentPosition();
if (old_duration == duration && videoView.isPlaying()) {
videoMessage.setVisibility(View.VISIBLE);
} else {
videoMessage.setVisibility(View.GONE);
}
old_duration = duration;

handler.postDelayed(runnable, 1000);
}
};
handler.postDelayed(runnable, 0);只需要判断当前播放位置与下一秒播放位置是否相等即可。所以通过这个方法即可实现使用VideoView监听缓冲状态,来实现出现缓冲中的提示了。不过,响应还是有点慢的。(默认是1秒)可以更改这里的时间来缩短响应时间。我使用的是0.5秒。
handler.postDelayed(runnable, 500);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息