Catching all possible exceptions while using android videoview - android

I am using android videoview to display a loop of videos, as per our requirement the video loop should continue even if one of the videos gives an error.
To catch any exception, I have included the relevant code in a try-catch block as shown in the below code. However, while testing all scenarios, I gave the wrong path to the videoview.setVideopath() but the exception is not caught. I can see in the android studio console that it reports the data source not found error, but catch block does not catch the exception. I also tried implementing onerrorlistener, it is also not called when this happens.
Could you please help me, I am attaching the relevant code and exception log, many thanks for your help.
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());
}
Exception log from the console :
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)

So, I just faced a similar issue, I needed to use a VideoView to play the video from a URL without any knowledge of if the URL was a valid video or not. I understand why you're asking about catching every exception as well. My VideoView would print out an IOException and another which I can't quite remember at the moment of this answer. To fix this, I used a very similar code to yours but in a different order. The setOnErrorListener is what solved my issue for me but I placed my OnErrorListener directly after my VideoPlayer initialization and before the setVideoPath.
This works because the setVideoPath is where the errors are handled, unfortunately, VideoView will print these errors to the log but it will not throw anything to crash the app (which I don't agree with or like one bit). Because of this, your setOnErrorListener should at least go before you set the path or there will be nothing for it to catch as the error would have been thrown already (The errors aren't thrown on start oddly enough.
To apply my solution to your code, I would change it to this:
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);
}

It is not a good style of code to catch a raw Exception, it is too broad to handle different error cases. However, for most of the IO operations IOException is the base exception, it is recommended to catch this.
As per java docs, we also need to consider IO operations can throw IOError. Error is not under the hierarchy of Exception, but both IOException and Error share Throwable as the base class. With this consideration, you can write your try-catch block as:
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
}
}
For more readability of the code, you can use multiple catch blocks:
try {
// Your code
} catch (IOException ioException) {
// handle IOException here
} catch (IOError ioError) {
// handle IOError here
}
Also, you can add throws clause to your method if you want to handle these exceptions later:
public void displayVideo() throws Throwable {
// Your code here
}
Note: This is not the perfect solution to capture all exceptions for your scenario. But, since your code also includes IO operations on the file, hence have used the above examples to explain how you can possibly implement your exception handling.

Related

RxJava Zip Operator Error Handling with Iterator

Background
I have a process that uses RxJava to get data from different locations based on a list. Each item is got through a different method (all returning Observables.). Due to having N items to get the logic operator to use is zip with an iterator.
The Problem
The code below works as expected but it seems "wrong" that I need a try-catch block to catch the Exception that is thrown by getBigFoo() - that returns a FooNotFoundException. Do not the other error related operators cover this, such as onErrorResumeNext() and onErrorReturn()?
private Observable<Bar> processFoos(List<Foo> foos) {
List<Observable<? extends IBar>> observablesToZip = new ArrayList<>();
for(Foo foo : foos) {
switch (foo.getType()) {
case BIG_FOO :
try {
observablesToZip.add(getBigFoo(foo.getId()));
} catch (Exception exception) {
//do nothing - but this seems wrong
}
}
}
return Observable.zip(observablesToZip, results -> mergeFoosIntoBar(results));
}
Attempts Made
The attempt below doesn't seem to catch the Exception generated. I don't understand why as there are technically no upstream or downstream items in the sequence, so Observable.empty() should work?
private Observable<Bar> processFoos(List<Foo> foos) {
List<Observable<? extends IBar>> observablesToZip = new ArrayList<>();
for(Foo foo : foos) {
switch (foo.getType()) {
case BIG_FOO :
observablesToZip.add(getBigFoo(foo.getId().onErrorResumeNext(Observable.empty()));
}
}
return Observable.zip(observablesToZip, results -> mergeFoosIntoBar(results));
}
You may want to use defer. getBigFoo should not throw an exception but instead return an Observable in error. So defer may help you to fix it :
Observable<IBar> obs = Observable.defer(() -> {
try {
return getBigFoo(foo.getId());
} catch (Exception ex) {
return Observable.error(ex);
}
});
observablestoZip.add(obs);
#dwursteisen was on to the right answer, but wasn't quite there.
My issue was that I was throwing a new FooNotFoundException:
throw new FooNotFoundException()
But what I needed to do was:
return Observable.error(new FooNotFoundException());
Then in my Zip function:
observablesToZip.add(getBigFoo(foo.getId())).onExceptionResumeNext(Observable.just(null);
Using the above combination means that the overall sequence does not abort and return an error when the individual Observables are resolved and potentially throw errors.
Could you make getBigFoo(foo.getId()) throw RuntimeException instead Exception?. All Exceptions on Pipeline must be captured, but not runtimeExceptions.
Take a look to this silly example
/**
* Here is a silly example how runtimeExceptions are not needed
*/
#Test
public void observableRuntimeException() {
Integer[] numbers = {0, 1, 2, 3, 4, 5};
Observable.from(numbers)
.doOnNext(number -> throwRuntimeException())
.doOnError(t -> System.out.println("Expecting illegal argument exception:" + t.getMessage()))
.subscribe();
}
private void throwRuntimeException() {
throw new RuntimeException();
}
you can see more examples here https://github.com/politrons/reactive

DexClassLoader, reload Code fails with Signal 7

I'm trying to build a plugin-System, where DexClassLoader is fetching code from other installed apks containing fragments(my plugins), and showing them in my host. This is working quite nice.
I also like to make the plugins hotswappable, this means I can change the code from a plugin, install it new and the host will notice and will load the new code. This also works, if I'm changing the code for the first time. (Although I thought it shouldn't, it seems I've got a wrong understanding of this code:
try {
requiredClass = Class.forName(fullName);
} catch(ClassNotFoundException e) {
isLoaded = false;
}
)
If i'm trying it a second time with the same plugin, the host shuts down at requiredClass = classLoader.loadClass(fullName); with something like
libc Fatal signal 7 (SIGBUS) at 0x596ed4d6 (code=2), thread 28814
(ctivityapp.host)
Does anybody has a deeper insight in the functionality of DexClassLoader and may tell me, what is happening here? I'm quite stuck at this.
Heres the full code of the method loading the foreign code:
/**
* takes the name of a package as String, and tries to load the code from the corresponding akp using DexclassLaoder.
* Checking if a package is a valid plugin must be done before calling this.
* The Plugin must contain a public class UI that extends Fragment and implements plugin as a starting point for loading
* #param packageName The full name of the package, as String
* #return the plugins object if loaded, null otherwise
*/
private Plugin attachPluginToHost(String packageName) {
try {
Class<?> requiredClass = null;
final ApplicationInfo info = context.getPackageManager().getApplicationInfo(packageName,0);
final String apkPath = info.sourceDir;
final File dexTemp = context.getDir("temp_folder", 0);
final String fullName = packageName + ".UI";
boolean isLoaded = true;
// Check if class loaded
try {
requiredClass = Class.forName(fullName);
} catch(ClassNotFoundException e) {
isLoaded = false;
}
if (!isLoaded) {
final DexClassLoader classLoader = new DexClassLoader(apkPath, dexTemp.getAbsolutePath(), null, context.getApplicationContext().getClassLoader());
requiredClass = classLoader.loadClass(fullName);
}
if (null != requiredClass) {
// Try to cast to required interface to ensure that it's can be cast
final Plugin plugin = Plugin.class.cast(requiredClass.newInstance());
installedPlugins.put(plugin.getName(), plugin);
return plugin;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
Many thanks in advance!
Not that it really matters (As nobody is actually viewing this), or that I even understand what's going on, but deleting the corresponding file of the plugin in dexTemp.getAbsolutePath() before reloading it solves the problem.
PS: Tumbleweed-Badge, YAY!

Need some explaining

So this is the weirdest thing ever to happen to me during programing. Yes I'm no pro at programing, but I'm learning as I go. I've got an app talking to a server, a socket in the main thread, reading is done in a separate class and thread and writing in a separate class with asynctask.
The problem is LocationManager. I could talk to server and write/read commands just fine, I implemented the LocationManager and its listener.
I then proceeded to implement a method to update my textview with the new coordinates on locatinChanged. So far so good. Thing is when I use the Emulator control in eclipse and send coordinates the app crashed with a stringOutOfBoundsException (I've programed for 3 years now never seen this). I looked at the code stepped through it and so on. Read the stacktrace, logcat, console and everywhere I could think of but it got me nowhere. Until I finally went to the readerthread which looks like this:
public class ReaderThread extends Thread {
public void run() {
new Thread(new Runnable(){
public void run(){
try {
//Establish a bufferedreader to read from the socket/server.
in = new BufferedReader(new InputStreamReader(socket.getInputStream()), 8 * 1024);
}
catch(Exception e) { e.printStackTrace(); }
//As long as connect is true.
while (connected) {
String line;
try {
//Try to read a line from the reader.
line = in.readLine();
System.out.println(in.readLine());
if (in == null) {
//No one has sent a message yet.
System.out.println("No data recieved");
}
else {
int i = 0;
//As long as someone is sending messages.
while((line = in.readLine()) != null ){
//Make a new Message.
Message msg;
msg = new Message();
//Set the object to the input line.
msg.obj = line;
//Set an id so it can be identified in the main class and used in a switch.
msg.what = i;
System.out.println("i is: "+i);
//Send the message to the handler.
Main.this.h.sendMessage(msg);
}
}
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}).start();
}
The variable i is in an if statement depending on what the server sent but I cut that out as it has nothing to do with this problem.
The problem is the freaking catch. When the catch is IOException, the app crashes. Out of dumb luck I changed this to Exception and printed e.message to catch the error and see what caused it. Thing is this change fixed it. How can switching IOException to just plain Exception fix a problem like this?
Its like with IOException the program says: "hey your not gonna catch the error but there is no error" but with Exception it says "Well now you could catch it so I'll proceed".
My app is working but I just can't grasp this, why and how does this happen?
You're essentially telling the application to catch the base Exception class. This means that any type of error will be caught, since all exception classes descend from that base type. Since StringOutOfBoundsException does not descend from IOException it was not being caught before and the error was not being caught. Instead of catching all exceptions, you might try the following:
try {
// Your code here...
} catch (IOException e) {
Log.e(TAG, "Caught an IOException!", e);
} catch (StringOutOfBoundsException e) {
Log.e(TAG, "Caught a string out of bounds Exception!", e);
}
I'm unable to determine what is actually throwing the StringOutOfBoundsException to begin with. It may be in the if statement that you cut out of your example.
while (connected) {
String line;
try {
//Try to read a line from the reader.
line = in.readLine();
System.out.println(in.readLine());
if (in == null) {
//No one has sent a message yet.
System.out.println("No data recieved");
}
The test for in == null is in a funny location. You should receive a NullPointerException if that test were to ever return true by nature of calling methods on it a few lines earlier. Obviously something is a little funny with this code.
You fail to save the return value from in.readLine() the second time you call it. I hope it did not contain anything useful. (Though, since you print the line, you obviously wanted to know what data it contained.)
Whatever that line was (from the first call to in.readLine()), it gets thrown away; there's nothing else in the loop that uses it before it is over-written on this line:
while((line = in.readLine()) != null ){
At this point, the two lines that you read are gone forever.
I'm not entirely sure what should be done to fix this; if it were me, I'd be sorely tempted to start over with a sheet of paper and sketch out what the method should be doing without looking at the existing code, then compare the sketch against the code to see which cases each one has overlooked.

android exception for validating file exist not working

I've been working with Eclipse ADT for about 2 months. In that time, I have a small utility that allows me to select an IP Address and Port, and then send a file to that combo. The utility works as intended, but when I type in the wrong file name, the application hangs.
#Override
public void run() {
if (data != null) {
this.send(data);
} else if (this.file != null) {
if (file.exists()) {
this.send(file);
} else {
transferError = new FileNotFoundException("The specified file could not be found");
}
}
}
I've even tried to do the following in hopes that one or the other would throw, but I am unsuccessful in both.
public void run() {
if (data != null) {
this.send(data);
} else if (this.file != null) {
if (file.exists()) {
this.send(file);
} else {
transferError = new FileNotFoundException("The specified file could not be found");
}
}try {
throw new Exception("blah blah blah");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I've jockeyed around the exception, I've added the one above, I've tried placing it in different places, and all unsuccessful. Again, I'm exceptionally new to this, and got here from basically mincing various tcp client codes. Aside of creating a way to throw the exception correctly, please help me understand why the first one isn't working and why the one you suggest is.
in your else block you aren't throwin the transferError you create.
throw transferError;
However you probably won't be able to do that because FileNotFoundException is a checked exception and the run() method doesn't declare any thrown exceptions. You probably need to find a different way to present the error to the user, like with a Toast or something.
Your second block doesn't work because you are catching the exception you throw.

TTS callback: dispatch completed to 1

I created a small TTS app implementing OnUtteranceCompleteListener and, while things seem to be working exactly as expected, I noticed the following on LogCat (one for each completed utterance):
03-01 20:47:06.436:
VERBOSE/TtsService(381): TTS callback:
dispatch completed to 1
Again, this seems to be benign but I don't understand what '1' means. All such lines for all utterances say "completed to 1", even for utterance IDs that are greater than 1.
What does '1' mean in this log?
BTW, this message is not generated by my code but rather by the TTS engine (Pico) itself.
Looking at the TTSService.java source code available at http://eyes-free.googlecode.com you can find the function dispatchUtteranceCompletedCallback():
private void dispatchUtteranceCompletedCallback(String utteranceId, String packageName) {
/* Legacy support for TTS */
final int oldN = mCallbacksOld.beginBroadcast();
for (int i = 0; i < oldN; i++) {
try {
mCallbacksOld.getBroadcastItem(i).markReached("");
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
try {
mCallbacksOld.finishBroadcast();
} catch (IllegalStateException e) {
// May get an illegal state exception here if there is only
// one app running and it is trying to quit on completion.
// This is the exact scenario triggered by MakeBagel
return;
}
/* End of legacy support for TTS */
ITtsCallbackBeta cb = mCallbacksMap.get(packageName);
if (cb == null) {
return;
}
Log.v(SERVICE_TAG, "TTS callback: dispatch started");
// Broadcast to all clients the new value.
final int N = mCallbacks.beginBroadcast();
try {
cb.utteranceCompleted(utteranceId);
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
mCallbacks.finishBroadcast();
Log.v(SERVICE_TAG, "TTS callback: dispatch completed to " + N);
}
1 is the current value of N, which is initialized by the return value from mCallbacks.beginBroadcast().
beginBroadcast() is a method of the class RemoteCallbackList and its documentation states that it:
Returns the number of callbacks in the
broadcast, to be used with
getBroadcastItem(int) to determine the
range of indices you can supply
Does this help?

Categories

Resources