在使用android视频视图时捕捉所有可能的异常



我使用android videoview来显示一个视频循环,根据我们的要求,即使其中一个视频出现错误,视频循环也应该继续。

为了捕获任何异常,我在try-catch块中包含了相关的代码,如下面的代码所示。然而,在测试所有场景时,我给了videoview.setVideopath((错误的路径,但没有捕捉到异常。我可以在android工作室控制台中看到,它报告了数据源未找到错误,但catch块没有捕捉到异常。我还尝试过实现onerrorlistener,当这种情况发生时也不会调用它。

你能帮我吗,我附上了相关的代码和异常日志,非常感谢你的帮助。

private void DisplayVideo_VideoView(){
try {
adplayer = (ResizableVideoView) findViewById(R.id.adplayer);
String MediaStorePath = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/Videos";
//   String videoPath = MediaStorePath + "/" + Root2Util.Videopathlist.get(CurrentMediaIndex).getFileName();
String videoPath = MediaStorePath + "/1" + Root2Util.Videopathlist.get(CurrentMediaIndex).getFileName();
//adplayer.setVideoPath(videopath[CurrentMediaIndex]);
adplayer.setVideoPath(videoPath);
adplayer.changeVideoSize(Root2Util.SCREEN_WIDTH, Root2Util.SCREEN_HEIGHT);
adplayer.setVisibility(View.VISIBLE);
adplayer.start();
adplayer.setKeepScreenOn(true);
adplayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
CurrentMediaIndex++;
//mp.reset();
if (CurrentMediaIndex == Root2Util.Videopathlist.size()) {
CurrentMediaIndex = 0;
}
playMedia();
//   ErrorHandlerAsyncTask ErrorTask=new ErrorHandlerAsyncTask();
//   ErrorTask.execute((Object)getApplicationContext(),(Object)String.valueOf(what));
return false;
}
});
} catch(Exception e) {
ErrorHandlerAsyncTask ErrorTask=new ErrorHandlerAsyncTask();
ErrorTask.execute((Object)getApplicationContext(),(Object)e.getMessage());
}

控制台的异常日志:

W/VideoView: Unable to open content: /storage/emulated/0/Download/Videos/1f0a9106d-d7d5-470c- 
b287-3e3cad7d13fb.mp4
java.io.IOException: setDataSource failed.
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1091)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1065)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1019)
at android.widget.VideoView.openVideo(VideoView.java:352)
at android.widget.VideoView.access$2100(VideoView.java:72)
at android.widget.VideoView$7.surfaceCreated(VideoView.java:628)
at android.view.SurfaceView.updateWindow(SurfaceView.java:580)
at android.view.SurfaceView.setVisibility(SurfaceView.java:256)
at root2tech.cloudplayer.HomepageActivity.DisplayVideo_VideoView(HomepageActivity.java:728)
at root2tech.cloudplayer.HomepageActivity.playMedia(HomepageActivity.java:958)
at root2tech.cloudplayer.HomepageActivity.access$200(HomepageActivity.java:78)
at root2tech.cloudplayer.HomepageActivity$5.run(HomepageActivity.java:571)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:935)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:730)

所以,我刚刚遇到了一个类似的问题,我需要使用VideoView从URL播放视频,而不知道URL是否是有效的视频。我理解你为什么问要抓住每一个例外。我的VideoView会打印出一个IOException和另一个我当时不太记得的IOException。为了解决这个问题,我使用了与您的代码非常相似的代码,但顺序不同。setOnErrorListener为我解决了问题,但我将OnErrorListen直接放置在VideoPlayer初始化之后和setVideoPath之前。

这是有效的,因为setVideoPath是处理错误的地方,不幸的是,VideoView会将这些错误打印到日志中,但它不会抛出任何导致应用程序崩溃的东西(我一点也不同意或喜欢(。正因为如此,您的setOnErrorListener至少应该在您设置路径之前进行,否则它将无法捕获任何错误,因为错误已经抛出(错误在启动时抛出得不够奇怪。

要将我的解决方案应用于您的代码,我会将其更改为:

private void DisplayVideo_VideoView(){
//initialize adplayer
adplayer = (ResizableVideoView) findViewById(R.id.adplayer);
//begin listening for errors
adplayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
CurrentMediaIndex++;
if (CurrentMediaIndex == Root2Util.Videopathlist.size()) {
CurrentMediaIndex = 0;
}
playMedia();

return false;
}
});
//build variables for readability
String MediaStorePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/Videos";
String videoPath = MediaStorePath + "/1" + Root2Util.Videopathlist.get(CurrentMediaIndex).getFileName();
//set path - If there is an issue with videoPath, the error should be thrown here
adplayer.setVideoPath(videoPath);
//final adplayer customizations
adplayer.changeVideoSize(Root2Util.SCREEN_WIDTH, Root2Util.SCREEN_HEIGHT);
adplayer.setVisibility(View.VISIBLE);
//begin the adplayer
adplayer.start();
adplayer.setKeepScreenOn(true);
}

捕获原始异常不是一种好的代码样式,它太宽泛,无法处理不同的错误情况。但是,对于大多数IO操作,IOException是基本异常,建议捕获此异常。

根据java文档,我们还需要考虑IO操作可以抛出IOError。Error不在Exception的层次结构下,但IOExceptionError都共享Throwable作为基类。考虑到这一点,您可以将try-catch块写为:

try {
// Your code
} catch (Throwable throwable) {
if (throwable instanceof IOException) {
// handle IOException here
} else if (throwable instanceof Error) {
if (t instanceof IOError) {
// handle IOError here
}
} else {
//This else will be reached only if you have any custom exceptions
}
}

为了提高代码的可读性,可以使用多个catch块:

try {
// Your code
} catch (IOException ioException) {
// handle IOException here
} catch (IOError ioError) {
// handle IOError here
}

此外,如果以后要处理这些异常,可以将throws子句添加到方法中:

public void displayVideo() throws Throwable {
// Your code here
}

注意:这不是捕获场景中所有异常的完美解决方案。但是,由于您的代码还包括对文件的IO操作,因此使用上面的示例来解释如何可能地实现异常处理。

最新更新