avatarFred Grott

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

3862

Abstract

</div><div id="542a"><pre>details.<span class="hljs-keyword">stack</span> <span class="hljs-keyword">as</span> StackTrace,</pre></div><div id="03ff"><pre>)<span class="hljs-comment">;</span></pre></div><div id="9f40"><pre>}</pre></div><div id="ab19"><pre>}</pre></div><div id="4e0a"><pre>}<span class="hljs-comment">;</span></pre></div><p id="232e"><b>We put a Zone.current call so that the error is passed to the Zone uncaught-handler, as all Flutter Framework errors will be uncaught exceptions.</b></p><p id="b4f5">Now, remember the main is in its own Zone.root isolate, so we need to set up an inner Zone for our runApp call:</p><div id="8300"><pre>runZonedGuarded&lt;Future&lt;<span class="hljs-literal">Null</span>&gt;&gt;(</pre></div><div id="c3f3"><pre>() <span class="hljs-keyword">async</span> {</pre></div><div id="a1a5"><pre>//Since we <span class="hljs-keyword">start</span> another <span class="hljs-type">zone</span> we need <span class="hljs-keyword">to</span></pre></div><div id="a5d5"><pre><span class="hljs-comment">//ensure that SkyEngine has fully loaded Flutter</span></pre></div><div id="ab5a"><pre>// <span class="hljs-keyword">and</span> <span class="hljs-keyword">it</span> needs <span class="hljs-built_in">to</span> be called here <span class="hljs-built_in">to</span> enable grabbing <span class="hljs-keyword">the</span> errors</pre></div><div id="2936"><pre>WidgetsFlutterBinding.ensureInitialized()<span class="hljs-comment">;</span></pre></div><div id="765e"><pre><span class="hljs-comment">// Service and other initializations here</span></pre></div><div id="b431"><pre>myLogger.<span class="hljs-built_in">info</span>(<span class="hljs-string">'app initialized'</span>);</pre></div><div id="3f3d"><pre>runApp(<span class="hljs-function"><span class="hljs-keyword">const</span> <span class="hljs-title">MyApp</span>())</span>;</pre></div><div id="d289"><pre>},</pre></div><div id="4d5f"><pre><span class="hljs-string">//</span> <span class="hljs-attr">ignore:</span> <span class="hljs-literal">no</span><span class="hljs-string">-empty-block</span></pre></div><div id="927a"><pre>(Object <span class="hljs-keyword">error</span>, StackTrace <span class="hljs-keyword">stack</span>) {</pre></div><div id="ae71"><pre>log(<span class="hljs-string">'<span class="hljs-subst">$error</span>.runtimeType <span class="hljs-subst">$stack</span>'</span>);</pre></div><div id="56e9"><pre>},</pre></div><div id="2056"><pre><span class="hljs-symbol">zoneSpecification:</span> ZoneSpecification(</pre></div><div id="80ad"><pre><span class="hljs-comment">// Intercept all print calls</span></pre></div><div id="74b9"><pre><span class="hljs-built_in">print</span>: (self, parent, zone, line) <span class="hljs-keyword">async</span> {</pre></div><div id="8157"><pre><span class="hljs-comment">// Include a timestamp and the name of the App</span></pre></div><div id="bfd8"><pre><span class="hljs-keyword">final</span> messageToLog = <span class="hljs-string">"[<span class="hljs-subst">${DateTime.now()}</span>] <span class="hljs-subst">$myAppTitle</span> <span class="hljs-subst">$line</span> <span class="hljs-subst">$zone</span>"</span>;</pre></div><div id="9677"><pre>// Also print <span class="hljs-keyword">the</span> message <span class="hljs-keyword">in</span> <span class="hljs-keyword">the</span> <span class="hljs-string">"Debug Console"</span></pre></div><div id="db42"><pre><span class="hljs-comment">// but it's ony an info message and contains no</span></pre></div><div id="a5a0"><pre><span class="hljs-comment">// privacy prohibited stuff</span></pre></div><div id="a8eb"><pre>parent.<span class="hljs-built_in">print</span>(zone, messageToLog);</pre></div><div id="4b5f"><pre>},</pre></div><div id="ac67"><pre>),</pre></div><div id="5852"><pre>)<span class="hljs-comment">;</span></pre></div><p id="7916"><b>We use the ZoneSpeci

Options

fication to redefine the console-dump(it’s print) to format the console output. And this is the full code:</b></p> <figure id="39a7"> <div> <div>

            <iframe class="gist-iframe" src="/gist/fredgrott/2187030c28e08185206ba73e31518800.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><h1 id="3523">Conclusion</h1><p id="d8c8"><b>This is just one part of the boilerplate you have to finalize for each app that you create. In another article, I will show you how to combine this with the Catcher plugin so that we can display a custom error widget to the app-user and pass on an app exception report to a third-party service.</b></p><h1 id="61ca">About Me, Fred Grott</h1><p id="3705"><b>I am a reformed Android, Java, Kotlin, and Front-End developer. I am a reformed ADHD’er and Code and Design Cowboy. Not only that, but I am organically creating my Flutter Developer Book chapters via Medium article writing, which is at:</b></p><p id="4224">https://fredgrott.medium.com</p><p id="a854">Code for the book series is being worked at a raw playground of:</p><div id="1e1f" class="link-block">
      <a href="https://github.com/fredgrott/flutter_design_and_arch_rosetta">
        <div>
          <div>
            <h2>fredgrott/flutter_design_and_arch_rosetta</h2>
            <div><h3>I am creating a Flutter Development and Design Book series and this is the huge repo for it.</h3></div>
            <div><p>github.com</p></div>
          </div>
          <div>
            <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*kffW8RKyUbO-BvVR)"></div>
          </div>
        </div>
      </a>
    </div><p id="134e">The more formalized almost ready for book code is at:</p><div id="114a" class="link-block">
      <a href="https://github.com/fredgrott/ddi_flutter">
        <div>
          <div>
            <h2>fredgrott/ddi_flutter</h2>
            <div><h3>This my more formalized version of a Rosetta Stone of Flutter Demos to encourage you to take a deep dive into flutter…</h3></div>
            <div><p>github.com</p></div>
          </div>
          <div>
            <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*bE9jxUr8bCLafFe9)"></div>
          </div>
        </div>
      </a>
    </div><p id="7758">and my GitHub profile is at</p><div id="6666" class="link-block">
      <a href="https://github.com/fredgrott">
        <div>
          <div>
            <h2>fredgrott - Overview</h2>
            <div><h3>I am startup front-end developer and designer. I am building some flutter apps and writing some flutter app developer…</h3></div>
            <div><p>github.com</p></div>
          </div>
          <div>
            <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*MZhtuCq9Q1Jtvg7t)"></div>
          </div>
        </div>
      </a>
    </div><p id="366e">And I can be DM’ed at:</p><div id="8eb9" class="link-block">
      <a href="https://keybase.io/fredgrott">
        <div>
          <div>
            <h2>fredgrott (Fred Grott) on Keybase</h2>
            <div><h3>What the heck is Keybase? Keybase comes with everything you need to manage your identity, create secure chats, and…</h3></div>
            <div><p>keybase.io</p></div>
          </div>
          <div>
            <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*1NAXCHEYCEMbjJMc)"></div>
          </div>
        </div>
      </a>
    </div></article></body>

Uncaught Exception Secrets, Zones

How do we process uncaught exceptions to well-behaved extensions? It’s a process where we discover an uncaught exception then change code to account for it; and, Zones has a role to play in this process.

Isolates and Zones, Oh My

It’s not true that Dart is single-threaded. What is true is that one thread is in an isolate. For example, the main function starts out in a Zone.root in a single isolate:

So what happens when we create another Zone in a child of main? Yes, we get a separate isolate which means that if we have an uncaught exception it does not take down the main function of the app as that is in a separate isolate.

The gist is if we have the right zone set up then we are able to debug our app by running it to see the uncaught exception show up in the IDE-console-log then re-write some code to handle that case and run the app again and see that exception disappear.

Using Zones

First, we set up an error handler to catch flutter exceptions:

FlutterError.onError = (FlutterErrorDetails details) async {
if (isInDebugMode) {
// In development mode simply print to console.
FlutterError.dumpErrorToConsole(details);
} else {
// In production mode report to the application zone to report to
// app exceptions provider. We do not need this in Profile mode.
// ignore: no-empty-block
if (isInReleaseMode) {
// FlutterError class has something not changed as far as null safety
// so I just assume we do not have a stack trace but still want the
// detail of the exception.
// ignore: cast_nullable_to_non_nullable
Zone.current.handleUncaughtError(
// ignore: cast_nullable_to_non_nullable
details.exception,
// ignore: cast_nullable_to_non_nullable
details.stack as StackTrace,
);
}
}
};

We put a Zone.current call so that the error is passed to the Zone uncaught-handler, as all Flutter Framework errors will be uncaught exceptions.

Now, remember the main is in its own Zone.root isolate, so we need to set up an inner Zone for our runApp call:

runZonedGuarded<Future<Null>>(
() async {
//Since we start another zone we need to
//ensure that SkyEngine has fully loaded Flutter
// and it needs to be called here to enable grabbing the errors
WidgetsFlutterBinding.ensureInitialized();
// Service and other initializations here
myLogger.info('app initialized');
runApp(const MyApp());
},
// ignore: no-empty-block
(Object error, StackTrace stack) {
log('$error.runtimeType $stack');
},
zoneSpecification: ZoneSpecification(
// Intercept all print calls
print: (self, parent, zone, line) async {
// Include a timestamp and the name of the App
final messageToLog = "[${DateTime.now()}] $myAppTitle $line $zone";
// Also print the message in the "Debug Console"
// but it's ony an info message and contains no
// privacy prohibited stuff
parent.print(zone, messageToLog);
},
),
);

We use the ZoneSpecification to redefine the console-dump(it’s print) to format the console output. And this is the full code:

Conclusion

This is just one part of the boilerplate you have to finalize for each app that you create. In another article, I will show you how to combine this with the Catcher plugin so that we can display a custom error widget to the app-user and pass on an app exception report to a third-party service.

About Me, Fred Grott

I am a reformed Android, Java, Kotlin, and Front-End developer. I am a reformed ADHD’er and Code and Design Cowboy. Not only that, but I am organically creating my Flutter Developer Book chapters via Medium article writing, which is at:

https://fredgrott.medium.com

Code for the book series is being worked at a raw playground of:

The more formalized almost ready for book code is at:

and my GitHub profile is at

And I can be DM’ed at:

Flutter
iOS
Android
Software Engineering
Software Development
Recommended from ReadMedium