Little More Error Handling
A Little More Framework for the Flutter Framework makes for better apps
Part of the ‘Little More’ Series, this article will detail the Error Handling available to you when using the Fluttery Framework.
Handle your errors. True, you’re the greatest programmer that ever lived, and your code will never crash. However, I’m seeing code out there that assumes everything will run as expected, and we know that’s not good. Your code must anticipate the unexpected. It must! Here’s how.
In the first screenshot below, we see a Fluttery Framework example app starting up. Note, that’s not your traditional runApp() function. The original runApp() function is called, but not before establishing some error handling first (see second screenshot below).
Even before that, when using Fluttery, if the Widget instantiated and passed to that runApp() function extends the class, AppStatefulWidget, it creates the AppErrorHandler class object already right in its constructor (see third screenshot). And so, right from the start, your app has an Error Handler ready to go! Tap the screenshot’s captions to view the code.
If you like, you’re then free to call the App’s Error Handler yet again (see below) and establish any third-party error handler (Firebase Crashlytics, Catcher 2, etc.). They will then catch errors for you in the fashion that they do.
The State of Error
In the video below, there’s an exception thrown with every tap of the button, but you’d never know it. The exception is recognized right there in the State class resulting in the counter incrementing correctly.
In Fluttery, every State object can perform its own error handling. Imagine a particular error is thrown in your app from time to time. A network drop for example. Whatever it may be, your app encounters an error in certain circumstances, but you’re ready for it. Your State object has a built-in error handler:
void onError(FlutterErrorDetails details) {
The video depicts the Fluttery Framework’s own example app. You can see in the first screenshot below, a FloatingActionButton widget (if not testing the app) will explicitly throw an Exception. The second screenshot is of the residing State object. Its Error handler calls the onPress() function in response to this particular error and successfully increments the counter.
It’s a very simple example, but it does demonstrate the potential here to modularize the error handling in your app. Isolating parts of your code more susceptible to error simply makes for a more reliable and more robust app.
Pass It On
The error now continues up the Widget tree. It may be handled by the State object, but every error is an ‘app error’ and will be logged by the App’s State object in its own onError() function. For example, the error introduced above is running from a phone emulator. Hence, the error is eventually reported in the IDE’s console screen. See below.
When I say ‘handled by the State object’, I mean acknowledges the error and may even address the error. However, any error must then propagate further up to the App’s Error Handler. You don’t want seemingly ‘handled’ errors stopped at a State object’s onError() function. Such an arrangement I feel would be prone to abuse — developers would whole-heartedly stop the propagation and ignore errors! That wouldn’t be good either.
No, the developers overseeing the app as a whole (i.e. with access to the App’s State object) should have the final say and meet each error in their own Error Handler. Note how Fluttery works for the lone developer as well as in a team environment.
Further, do you see how Fluttery naturally compartmentalizes the app’s code? I feel Flutter is naturally ‘State-object-centric’ as the Google engineers intended. Each State object could stand alone as its own particular app in a sense, and this concept is only accentuated using the Fluttery Framework package.
As for the App State object, it has two Error Handlers. You may have established a third-party Error Handler, and they will catch errors certainly, but these errors will also pass through the onErrorHandler() function and the inErrorHandler() function if you’ve implemented them.
You’ll find the App’s State object has a number of functions prefixed with ‘on’ and ‘in’ (see Little More Adaptive). Traditionally, the ‘on’ version, if implemented, will supersede the ‘in-line’ version. However, I’ve placed so much emphasis on Error Handling that I allow for both the ‘on’ and ‘in-line’ versions to run in turn. In my mind, you can’t have enough Error Handling! Implement them both if you want.
The two screenshots below demonstrate how they’re used. The ‘on’ version is in the first screenshot below — a standalone function called after the third-party Error Handler if any is called, or it’s called on its own in response to an error in the app. The second screenshot displays the ‘in-line’ version. It’s always found passed to the App State’s constructor, and is always called right after the ‘on’ version.
You can see I’ve even overridden the State object’s onError() function. You’re free to override it if you must. However, please don’t ignore errors — it won’t benefit anyone in the end. Regardless, you have complete power over your app’s error handling.
With Fluttery, you’ve no excuses. Despite your obvious prowess, errors will occur in your code. Fluttery invites you to acknowledge errors where they’re likely to occur — right in the running State object. They then go to the App’s first State object. It’s the class that governs not only how the app looks and behaves, but how it handles its errors as well.
Cheers.