17

I'm trying to implement valid exception handling in my monodroid app which is written with Xamarin.Android plugin for Visual Studio.

I'm trying to handle 2 types of exceptions:

  1. at foreground (UI) thread
  2. at background (threadpool) thread

In both cases at global handler I'm want to:

  • Logging - (submitting analytics event)
  • User Notification - (alert)

After certain investigation I have found some answers here, here and here but nothing except AndroidEnvironment.UnhandledExceptionRaiser and AppDomain.UnhandledException was proposed and it doesn't work in all cases.

I created short sample where I'm trying to use both handlers:

AppDomain.CurrentDomain.UnhandledException += (s,e)=>
{
    System.Diagnostics.Debug.WriteLine("AppDomain.CurrentDomain.UnhandledException: {0}. IsTerminating: {1}", e.ExceptionObject, e.IsTerminating);
};

AndroidEnvironment.UnhandledExceptionRaiser += (s, e) =>
{
    System.Diagnostics.Debug.WriteLine("AndroidEnvironment.UnhandledExceptionRaiser: {0}. IsTerminating: {1}", e.Exception, e.Handled);
    e.Handled = true;
};

And then on button click I added the following code to raise both types of exceptions:

//foreground exception
throw new NullReferenceException("test nre from ui thread.");
//background exception
ThreadPool.QueueUserWorkItem(unused =>
{
    throw new NullReferenceException("test nre from back thread.");
});

As a result I have different behavior for both types of exceptions:

  1. foreground:
    • both handlers are raised
    • it is impossible to prevent app from being crashed - it will be crashed any way (e.Handled = true is just ignored)
  2. background:
    • only the second handler is raised
    • app doesn't crash

In my case I couldn't wrap every user action in try-catch, especially background tasks. I have business login which should be interrupted in case of error and it is exactly what I expect from runtime. Same time I want to handle those exception on the top level in one place, log them (based on my our business rules) and continue app execution.

How to handle both exception and still have ability to keep app alive (prevent crash).

You can find complete code sample here: https://dl.dropboxusercontent.com/u/19503836/UnhandledException.zip

Thank you for your advice. Any help appreciated. TIA!

Community
  • 1
  • 1
Mando
  • 11,414
  • 17
  • 86
  • 167
  • 6
    This approach to exception handling is extremely poor design. Exceptions should be handled where they are raised and expected, not globally. Once the exception bubbles up to a global handler, you've lost all context and all hope of recovering state. – 323go Oct 22 '13 at 02:36
  • 2
    Thank you for your opinion but I couldn't agree with. I do understand and I do agree that I should handle exception BEFORE it lost a context but I don't agree to handle exception where they raised. Imaging I have DataAccess, Business Logic and UI, and I have button on UI level which initiate some dataaccess operation, then processed by business logic and finally result displayed on UI. If any error occurs on dataaccess level I want my dataaccess and business logic to be interrupted and result to be displayed on UI level. Exception is designed not to check for error after every method call... – Mando Oct 22 '13 at 14:48
  • I do agree that I should handle this error where I expected - at UI level, but not where it was raised (at dataaccess level). In my question I'm talking about general approach for bad error handling on UI level (imaging that UI error handler failed to log error). In this case I still want my app to notify user about it, have this subsequent error logged and have my app not crashed (failure to log an error is not a critical issue in my case). What I want is to decide my self if application should be terminated when unhanded exception raised. – Mando Oct 22 '13 at 14:52
  • 2
    And as I said before the general scenario is not to recover but log error and notify user about it - BUT NOT A SILENT APP CRASH. Silent crash - this is a bad architecture design. – Mando Oct 22 '13 at 14:53
  • 1
    @323go I'm new to Android development, so help me understand the alternative: How do you handle unexpected errors in your app? Do you wrap every user action (button click event handler, etc.) in a try/catch, or is there another way to do a "If all else fails, at least show the user an exception message?" – pettys Dec 16 '13 at 22:06
  • @pettys, ideally, your code shouldn't have to rely on exception handing to handle user-input. It may be tedious, but it's not difficult to sanity-check user actions. You need to wrap system actions, such as file-io or network communication so that you can recover gracefully -- the recovery will differ based on context, so a global exception handler wouldn't help you, and you'll need to handle this were the exception may occur. – 323go Dec 18 '13 at 14:39
  • @323go, I agree that you should handle expected errors when you can, and I agree that there is no graceful recovery without context, but I strongly disagree that "a global exception handler wouldn't help you." Any code can blow up at any time (eg, OutOfMemoryException, etc.). Graceful, context-specific error handling is good, but some things *will* slip through all that, and it's important to not simply crash, but to at least tell the user, "Whoa! Something bad has happened!" and then surface the exception information somewhere for fixing. There should be a global hook for that. – pettys Dec 18 '13 at 18:33
  • There **is** a global hook for that. Android will throw up a dialog telling you that the app has stopped, and the developer console will have the crash-report. Please read the question again; the poster wanted to avoid a crash altogether. – 323go Dec 18 '13 at 18:58
  • @323go I don't think what you described is a hook. I use "hook" as an API mechanism where I can inject my own code. Other app frameworks on other .NET platforms (eg, WinForms, ASP.NET, WPF) provide global error hooks, and provide options to keep the app running even when an uncaught, unexpected exceptions happen. Based on that experience, I'm surprised that (1) Xamarin/Android doesn't have a clean one, and (2) when people ask about it they're told it's an extremely poor idea. I guess the bottom line is I disagree that global exception handling as a last resort is a bad idea. – pettys Dec 20 '13 at 21:16
  • @323go a tool like Sentry or Rollbar relies on this behavior. Recording errors you didn't anticipate isn't bad design, it's good business. – Chris Pfohl Jul 26 '17 at 18:13

2 Answers2

9

These event handlers aren't designed to let you recover from the exception, they're a last resort to give you an opportunity to do something like writing to an error log before the application is terminated.

You've mentioned that you want to log errors - that should work fine, but displaying an error to the user might not be possible because your Application will have reached a point where it is not even able to do that.

As the comment on your question mentions, it is a bad idea to handle exceptions like this.

While you might have a very specific expectation of when this is going to be called, your App could throw an exception at any point - and for any reason. It's impossible to design it so that it handles everything correctly.

Even if you could write something to deal with any exception safely, your App will still be terminated because of the unhandled exception.

The Microsoft documentation for AppDomain.CurrentDomain.UnhandledException gives some more information on this:

http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx

Daveoc64
  • 403
  • 5
  • 14
  • Thanks, you are absolute right, nobody could guarantee that his error handling logic will handle everything but I do want to guarantee that this critical cases will be logged and user will be notified (even right before app crash, but still without silent crash). – Mando Oct 22 '13 at 14:59
  • 1
    Implementing both of these methods should let you do the logging you want (I have used that in my Xamarin.Android apps), but you'll almost certainly find that any sort of UI - AlertDialog, Toast or a new Activity can't be displayed once the App has reached this state. – Daveoc64 Oct 22 '13 at 15:57
  • 1
    That was my concern. Thank you for details. So silent crash in critical cases is the Android way to notify user about critical errors :( . In Windows Phone for example you can log, notify and peacefully terminate a process when received unhanded error. – Mando Oct 22 '13 at 18:35
  • 2
    @Daveo64 Global exception handling is very important in case something you never plan for happens in runtime. My Windows Phone applcations have NEVER crashed. Why should they? Rather than crashing, all my apps display a notification to the user about the error and then ask if the user want to close the app or continue using it. Please tell me, is this not polite enough? Android makes me sick as i cannot find same solution. – Shittu Joseph Olugbenga May 14 '15 at 14:19
3

@Daveoc64 - I disagree with you (and others) that have stressed that global handling of uncaught exceptions is a bad idea - i'd say its a necessity for UI applications. It doesn't negate proper exception handling at the method level (i.e where you can handle and recover from specific exceptions in which context is very important as you stressed) - but it's used in addition to it, as sometimes, when an exception occurs, there is no recovery for the application. Therefore putting a try / catch in code to catch an exception that you cannot recover from is pointless - as whatever you put inside that catch block - you'd have to copy and put inside all other catch blocks for the same sort of unrecoverable errors - i.e display a prompt to the user and gracefully exit.. Why repeat that sort of handling throughout the entire code base over and over again - its rediculous - a global exception handler to cater for that kind of concern makes much more sense!

Darrell
  • 1,905
  • 23
  • 31
  • 1
    As noted before, you simply aren't in control when an unexpected exception happens. You don't know what's going on and your program can't possibly know either. Any attempt to recover from the error is at best futile and potentially dangerous, as it could cause your application to behave incorrectly and cause data loss. – Daveoc64 Jul 14 '15 at 10:27
  • @Daveoc64 - i'm not talking about attempting to recover.. As i've written above, i'm talking about a graceful exit procedure. Perhaps that means attempoting to write the exception details to your logger of choice, displaying a "sad face" smiley to the user with apologies informing them the program must exit. – Darrell Jul 15 '15 at 16:20
  • 1
    Again, it has already been noted that you can write exception details to a logging mechanism in virtually all cases, but the reality with Android is that the OS simply won't let you do anything with the UI when an App crashes. As far as it's concerned, you've messed something up and it has a way of dealing with that for all applications - a standard OS dialog box. If you really feel the need to show the user a custom message, consider logging the crash somewhere you can query, then show a message the next time they start your App. – Daveoc64 Jul 16 '15 at 08:15
  • 1
    @Daveoc64 - I prefer this answer i.e its an android limitation that you cannot display UI in such a situation, i was reacting to suggestions that merely wanting to do so was "bad design" - thats more an opinion that i disagree with having implemented many a graceful application exit routine! Thank you for your answers. – Darrell Jul 17 '15 at 10:12