Android: How to check for a specific exception? - android

How to check for a specific exception, e.g. SocketException with message "Socket closed"? We can compare strings like this:
if (exception.getMessage().equals("Socket closed"))...
but is there some more elegant method, like comparing error codes, or comparison with constant exception value?
Except if SocketException is always "Socket closed", but in docs it states that this class is a superclass for all socket exceptions, so there is more than one.
UPDATE:
I don't want to check for exception class. If I do, I would use specialized catch rather than to check tor a class explicitly:
catch (SocketException ex) { ... }
I want some more elegant method to distinct two exceptions which are instances of the same class, not by comparing strings like this:
try {
int i = 2;
if (i == 1) throw new SocketException("one");
else if (i == 2) throw new SocketException("two");
}
catch (SocketException ex) {
if (ex.getMessage().equals("one")) { ... }
}
In this particular case I throw exceptions to show what is it about, but in reality it can be code not controlled by me.
Also I noticed that exception message in one particular case method threw "Socket closed", in another different method threw "Socket is closed". So it's not so reliable to stick to the message either.

Your question has different approaches, depending on what you are trying to achieve. The simplest method for determining if you have the exception you want is to use instanceof since an Exception is a class as well, i.e.:
if (myException instanceof SocketException) {
...
}
However, you then add the requirement of the contents of the message or the possibility that the Exception thrown is actually a subclass of the Exception of interest to you. In the case of a "subclass" you can check if it is a subclass with:
if (myException instanceof SocketException &&
myException.getClass() != SocketException.class) {
// then I'm an instance of a subclass of SocketException, but not SocketExcpetion itself
}
Or conversely, only evaluate for the parent class:
if (myException instanceof SocketException &&
myException.getClass() == SocketException.class) {
// then I'm an instance of the class SocketException, and not a cubclass of SocketExcpetion!!
}
These serve as the "error codes" you seem to be looking for - the identification of the class, with certainty.
However, if you really are interested in the human-readable error contents, then the solution you have should be your implementation. That seems unlikely, but sometimes that is what is required.

You can use:
exception.getClass().getSimpleName() and compare it to SocketException
Hope this helps.

Related

Handle IOException inside function

I have a method which copies some files from shared memory to internal app memory using the library FileUtils.
The goal is handling IOException in order not to crash the app: it's acceptable if some files are not copied out of the total number.
In the second snippet below there is the called method where the exception is handled.
I need to know 2 things:
a) is there a way to handle the exception only in the called method
and not also in the calling code?
b) in your opinion the exception handling is correct or do I need to add some other code?
Below is the code:
try {
copyfilesfromshared(context);
} catch (IOException e) {
e.printStackTrace();
}
public void copyfilesfromshared(Context context) throws IOException {
for (int ii = 0; ii < numfiles; ii++) {
try {
FileUtils.copyFileToDirectory(files[ii], dirwrite);
} catch (IOException e) {
e.printStackTrace();
}
}
}
is there a way to handle the exception only in the called method and not also in the calling code?
If you handle the exception in copyfilesfromshared() function you do not need to declare throws IOException
public void copyfilesfromshared(Context context) {
for (int ii = 0; ii < numfiles; ii++) {
try {
FileUtils.copyFileToDirectory(files[ii], dirwrite);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then you can use it normally, without declarin try {...} catch(...) again:
copyfilesfromshared(context);
in your opinion the exception handling is correct or do I need to add some other code?
This looks fine to me, but better check the signature of FileUtils.copyFileToDirectory if it throws any other exception as well, you maybe want to catch here too.
Beside that, it is totally on your side where you wanna handle the exception, but in general the earlier the better.
Heyy,
For your first question
a) is there a way to handle the exception only in the called method
and not also in the calling code?
There is a choise between throwing the IOException from the called method OR
to implement try/catch inside method.
And thats your problem
You are choosing both options instead of one, So just choose one.
And about 2 question
b) in your opinion the exception handling is correct or do I need to
add some other code?
Exception handeling is best at this moment, So don't think and other thought
And that's all!!

How to effectively group non fatal exceptions in Crashlytics (Fabrics)?

We are using Crashlytics in our app as the crash reporting tool.
For Android native crashes, it's working fine and grouping the crashes correctly.
Our app also has few components in react-native. For the crashes which occur in these components, we catch them and then log them to Crashlytics as non-fatal exceptions.
public class PlatformNativeModuleCallExceptionhandler implements
NativeModuleCallExceptionHandler {
#Override
public void handleException(Exception e) {
try {
.
.
.
Crashlytics.logException(new Exception(exceptionString));
} catch (Exception ex) {}
}
Crashes are getting logged in Crashlytics dashboard, but it's showing all the crashes inside a single tab. These might be different crashes of the same or different react-native components.
Due to this we are not able to find out the instances of a particular crash. Need to manually go through each instance of the crash.
I guess it takes the name of the class where exception gets created, in this case PlatformNativeModuleCallExceptionHandler.
I tried creating my own custom exception class but that also did not help.
Does anybody know how we can group the non fatal exceptions better here?
All the similar crashes should be grouped together with their total instances.
Crashlytics uses the method and crash line number to group crashes, so if you have an exception handler method for all of your non-fatals, they'll be grouped together. There isn't currently a workaround for this.
Best way I've found to do this is to manually chop the shared parts of the stacktrace off:
private fun buildCrashlyticsSyntheticException(message: String): Exception {
val stackTrace = Thread.currentThread().stackTrace
val numToRemove = 8
val lastToRemove = stackTrace[numToRemove - 1]
// This ensures that if the stacktrace format changes, we get notified immediately by the app
// crashing (as opposed to silently mis-grouping crashes for an entire release).
check(lastToRemove.className == "timber.log.Timber" && lastToRemove.methodName == "e",
{ "Got unexpected stacktrace: $stackTrace" })
val abbreviatedStackTrace = stackTrace.takeLast(stackTrace.size - numToRemove).toTypedArray()
return SyntheticException("Synthetic Exception: $message", abbreviatedStackTrace)
}
class SyntheticException(
message: String,
private val abbreviatedStackTrace: Array<StackTraceElement>
) : Exception(message) {
override fun getStackTrace(): Array<StackTraceElement> {
return abbreviatedStackTrace
}
}
This way the message can be parameterized Timber.e("Got a weird error $error while eating a taco") and all of that line's calls will be grouped together.
Obviously, numToRemove will need to change depending on your exact mechanism for triggering nonfatals.
I resolved this by setting a custom stack trace to the exception. A new Exception(exceptionMessage) will create the exception there itself, what we did was to throw an exception which in catch called my counterpart of handleException() with the actual stack trace furnished in the exceptionMessage. Some parsing and the exceptionMessage can be used to set the stack trace on the newly created exception using exception.setStackTrace(). Actually, this was required in my project only because it is cross-language, for regular projects, simply passing the exception thrown and caught at the place of interest should work.
Crashlytics groups by the line number that the exception was generated on and labels it with the exception type. If you know all the types of the exceptions you can generate each one on a different line. And you could also map your strings to custom Exception types to make it more easy to identify them in Crashlytics.
Here's an example:
public void crashlyticsIsGarbage(String exceptionString) {
Exception exception = null;
switch(exceptionString) {
case "string1": exception = new String1Exception(exceptionString);
case "string2": exception = new String2Exception(exceptionString);
case "string3": exception = new String3Exception(exceptionString);
case "string4": exception = new String4Exception(exceptionString);
default: exception = new Exception(exceptionString);
}
Crashlytics.logException(exception);
}
class String1Exception extends Exception { String1Exception(String exceptionString) { super(exceptionString); } }
class String2Exception extends Exception { String2Exception(String exceptionString) { super(exceptionString); } }
class String3Exception extends Exception { String3Exception(String exceptionString) { super(exceptionString); } }
class String4Exception extends Exception { String4Exception(String exceptionString) { super(exceptionString); } }
BTW, Crashlytics will ignore the message string in the Exception.
I was looking into this just now, because the documentation says:
Logged Exceptions are grouped by Exception type and message.
Warning:
Developers should avoid using unique values, such as user ID, product ID, and timestamps, in the Exception message field. Using unique values in these fields will cause a high cardinality of issues to be created. In this case, Crashlytics will limit the reporting of logged errors in your app. Unique values should instead be added to Logs and Custom Keys.
But my experience was different. From what I found out, what Alexizamerican said in his answer is true, with a small caveat:
Issues are grouped by the method and line where the exception was created, with the caveat that it is the root cause of the exception that is being taken into account here.
By root cause I mean this:
public static Throwable getRootCause(Throwable throwable) {
Throwable cause = throwable;
while (cause.getCause() != null) {
cause = cause.getCause();
}
return cause;
}
Therefore, if you did:
#Override
public void handleException(Exception e) {
// ...
Crashlytics.logException(e);
}
That should correctly group the exceptions together.
Furthermore, if you did:
#Override
public void handleException(Exception e) {
// ...
Crashlytics.logException(new Exception(exceptionString, e));
}
That would also correctly group the exceptions, because it would look at e or its cause, or the cause of that, and so on, until it reaches an exception that doesn't have any other cause, and look at the stack trace where it was created.
Finally, unlike what miguel said, exception type or message doesn't affect grouping at all in my experience. If you have FooException("foo") at some particular line in a particular method, and you replace it with BarException("bar"), the two will be grouped together, because the line and method didn't change.

Change language to Firebase exceptions

I'm calling to a Firebase method and in case of Exception I want to return the exception message in Spanish but task.getException().getMessage() is returning it in English instead.
Snippet code:
if (task.isSuccessful()) {
// do something
} else {
Toast.makeText(context, task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
Do I have to change something in Firebase configuration?
Thanks in advance
You can throw the Exception returned by task.getException inside a try-catch-block. All the exeptions that are thrown are in english. Below, each type of Exception that may be thrown by the method you are using.
I have uses an example from the OnCompleteListener for the createUserWithEmailAndPassword() method. Please see the follwing code:
if(!task.isSuccessful()) {
try {
throw task.getException();
} catch(FirebaseAuthWeakPasswordException e) {
//do somethig
} catch(FirebaseAuthInvalidCredentialsException e) {
//do somethig
} catch(FirebaseAuthUserCollisionException e) {
//do somethig
} catch(Exception e) {
Log.e("TAG", e.getMessage());
}
}
Hope it helps.
getLocalizedMessage() does give you the description of the exception (the name is given by task.getException().getClass().getSimpleName()) but still in English (therefore with no difference from getMessage()).
In order to make use of its "localized" features, you first need to override the method according to your needs.
You can see a complete example of how to do that here, although for the simple purpose mentioned here, I would definitely stick with Alex's solution.

Throw exception and allow to proceed in method further

I was working on some validation. There is some mandatory fields and some of them are optional. For mandatory fields, I'm throwing exception, but for optional fields, I've to print warning and have to proceed further in my method. I'm not getting any way to doing warning part. Can someone help on it?
public void method(String param1, String param2){
if(param1 == null){
throw new IllegalArgumentException("mandatory field");
}
//Here for param2, I want to throw eception, but want to proceed further to next line.
//Execute my code here
}
This is not how exceptions work. There are several ways to solve it:
Just don't use exceptions and print your error instead (println() or some textfield, toast or whatever)
Place a boolean marker saying that param2 failed and throw your exception at the end of the method
m_param2 = true
//...
if (param2 == null) {
m_param2 = false
}
// you proceed here
if (!m_param2){
// throw exception
}
Use submethods for the parameter-check which always throw an exception when errors occur and catch the error in your main-method and decide what to do then.
For me case 3 does not make that much sense but that depends on how and when you want to print the message. If you have something in the parent layer (the code that runs your method) that automatically generates the error-message when an exception occurs, I would stick to my second suggestion.
In general I think that missing optional parameters are no real error case so that no exception should be thrown. The method-caller needs to pass the parameter anyhow (though it can be null, of course).
throw is a keyword which finishes the method execution you cant continue by throwing an exception you can use an interface to do what you want
public void method(String param1, String param2,Listener listener){
if(param1 == null){
listener.IllegalArgumentException("mandatory field");
return;
}
listener.IllegalArgumentException("mandatory field");
//Execute my code here
}
interface Listener{
void IllegalArgumentException(String string);
}
You can use
try{
} catch (Exception e){
// you can ignore if you want to
}finally {
//rest of your code here
}
try the below code let me know if any issues.
public void method(String param1, String param2){
if(param1 == null){
throw new IllegalArgumentException("mandatory field");
}
if(param2 == null) {
Log.d("Error", "param2 is null");
}
}

Android MVP: Error Handling from Model class / manually trigger error

I have read the articile , and the great solution provided is working perfectly in Activity environment.
I tested it with
int a = 1/0;
in onCreate. And the custom exception handler did triggered.
Currently my app adopted MVP architecture. There are some codes implemeted in Model or Presenter layer like
try {
data = getStringFromFile(fileLocation);
} catch (Exception e) {
e.printStackTrace();
}
which might throw exception. However, the exceptions that caught within Presenter or Model layer is not triggering the default exception handler.
What should I do in order to makes the throwable exception from Model or Presenter layer triggers the custom UncaughtExceptionHandler I had created?
And also, is there anyway to trigger the custom UncaughtExceptionHandler manually by using my self defined exception.
Wrap the code in your presenter in try catch and then throw the exception from catch block to handle it by the parent class:
public void getData() throws Exception
try {
int a = 1/0;
} catch (Exception e) {
throw e;
}
}

Categories

Resources