38

Is it possible to make global error handling that will show user-friendly error page instead of showing red exception?

I already made error handling (here) that will report exception to the backend but what I really would like to achieve is to hide red exception and show something a little bit frendlier.

krishnaacharyaa
  • 14,953
  • 4
  • 49
  • 88
Anis Alibegić
  • 2,941
  • 3
  • 13
  • 28
  • Why not display an `alertDialog` which displays a user-friendly message in the production else of the `_reportError` method? – soupjake Nov 16 '18 at 09:20
  • AlertDialog needs the `context` object. How I'm gonna get `context` object inside `_reportError` method? – Anis Alibegić Nov 16 '18 at 09:24
  • Pass it through as a parameter? I.e. `Future _reportError(dynamic error, dynamic stackTrace, BuildContext context) async {}` – soupjake Nov 16 '18 at 09:28
  • `onError: (error, stackTrace) { _reportError(error, stackTrace); });` Is it possible to get it in onError method also since I'm using `runZoned`? – Anis Alibegić Nov 16 '18 at 09:31
  • Are you able to pass it in like `_reportError(error, stackTrace, BuildContext context);`? – soupjake Nov 16 '18 at 09:34
  • `_reportError` is called in `onError` method. I need it to recieve the `context` in `onError` method first, only then I can pass it to `_reportError` method. – Anis Alibegić Nov 16 '18 at 09:38
  • Mmm maybe this post can provide an answer: https://stackoverflow.com/questions/52223152/how-to-show-a-snackbar-from-async-executions-when-no-context-is-available – soupjake Nov 16 '18 at 09:51
  • I will try that. I really hope it won't show both errors, snackbar and the red exception. Thanks. – Anis Alibegić Nov 16 '18 at 09:54

2 Answers2

53

Official docs:

When an error occurs during the build phase, the ErrorWidget.builder callback is invoked to build the widget that is used instead of the one that failed. By default, in debug mode this shows an error message in red, and in release mode this shows a gray background.

You can define it in the builder method of the MaterialApp widget.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class CustomError extends StatelessWidget {
  final FlutterErrorDetails errorDetails;

  const CustomError({
    Key key,
    @required this.errorDetails,
  })  : assert(errorDetails != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        child: Text(
          "Something is not right here...",
          style: const TextStyle(
            color: Colors.white,
            fontWeight: FontWeight.bold,
          ),
        ),
        padding: const EdgeInsets.all(8.0),
      ),
      color: Colors.red,
      margin: EdgeInsets.zero,
    );
  }
}

class MyApp extends StatelessWidget {
  MyApp({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      builder: (BuildContext context, Widget widget) {
        ErrorWidget.builder = (FlutterErrorDetails errorDetails) {
          return CustomError(errorDetails: errorDetails);
        };

        return widget;
      },
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        children: <Widget>[
          Text(
            'Welcome,',
            style: Theme.of(context).textTheme.headline6,
          ),
          FirstName(),
        ],
        padding: const EdgeInsets.all(30.0),
      ),
    );
  }
}

class FirstName extends StatelessWidget {
  FirstName({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text(null);
  }
}

This is how it looks:

Before and after (click to enlarge)

Anis Alibegić
  • 2,941
  • 3
  • 13
  • 28
  • How to test this? What kind of red exception here? – stuckedunderflow Jan 14 '19 at 11:23
  • 1
    You can simply throw an exception and instead of the red exception it will show user friendly message. – Anis Alibegić Jan 14 '19 at 11:54
  • Oo ok I'll try because so far when I throw exception only on console never able to get something on UI which is now I'm digging on this – stuckedunderflow Jan 14 '19 at 15:25
  • Is it necessary to override `builder` in MaterialApp as well? – emen Apr 05 '19 at 07:59
  • Yes if you want to use the ThemeData. If you don't care about ThemeData then use the previous code. – Anis Alibegić Apr 05 '19 at 09:00
  • @Spectarion have you tried the solution on `release` mode. No error text in `release` mode (empty white screen) – Yi Doe May 13 '19 at 12:22
  • I make an example updated, check https://dartpad.dev/b4b2bae9438d5a9c238c467f6623cfca?. @AnisAlibegić can you update youy code to latest versions?! – Felipe Sales Jul 25 '23 at 23:44
  • @FelipeSales Not seeing any code other that default DartPad template? Are you sure you created a gist with that code and shared the correct URL? – Anis Alibegić Jul 30 '23 at 10:47
  • @AnisAlibegić stranger, really opening on anonym window not has content. You can see here: https://gist.github.com/felipecastrosales/b4b2bae9438d5a9c238c467f6623cfca. . I think that this is a bug. – Felipe Sales Jul 30 '23 at 13:43
5

Building on Anis Alibegić's answer:

  1. Added Scaffold. Without Scaffold the message appears on top of previously rendered content.
  2. Moved more code to the helper method.

Code:

void setErrorBuilder() {
  ErrorWidget.builder = (FlutterErrorDetails errorDetails) {
    return Scaffold(
        body: Center(
            child: Text("Unexpected error. See console for details.")));
  };
} 

class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     setErrorBuilder();

     return MaterialApp(
       builder: (BuildContext context, Widget widget) {
         setErrorBuilder();    
         return widget;
       },
       title: 'Flutter Demo',
       home: MyHomePage(title: 'Flutter Demo Home Page'),
     );
   }
 }
Anis Alibegić
  • 2,941
  • 3
  • 13
  • 28
polina-c
  • 6,245
  • 5
  • 25
  • 36