Show user-friendly error page instead of exception in Flutter
Asked Answered
B

2

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.

Braque answered 16/11, 2018 at 9:9 Comment(8)
Why not display an alertDialog which displays a user-friendly message in the production else of the _reportError method?Flaherty
AlertDialog needs the context object. How I'm gonna get context object inside _reportError method?Wight
Pass it through as a parameter? I.e. Future<Null> _reportError(dynamic error, dynamic stackTrace, BuildContext context) async {}Flaherty
onError: (error, stackTrace) { _reportError(error, stackTrace); }); Is it possible to get it in onError method also since I'm using runZoned?Wight
Are you able to pass it in like _reportError(error, stackTrace, BuildContext context);?Flaherty
_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.Wight
Mmm maybe this post can provide an answer: #52223652Flaherty
I will try that. I really hope it won't show both errors, snackbar and the red exception. Thanks.Wight
B
54

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)

Braque answered 5/12, 2018 at 20:28 Comment(9)
How to test this? What kind of red exception here?Leban
You can simply throw an exception and instead of the red exception it will show user friendly message.Wight
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 thisLeban
Is it necessary to override builder in MaterialApp as well?Hefner
Yes if you want to use the ThemeData. If you don't care about ThemeData then use the previous code.Wight
@Spectarion have you tried the solution on release mode. No error text in release mode (empty white screen)Cheapjack
I make an example updated, check dartpad.dev/b4b2bae9438d5a9c238c467f6623cfca?. @AnisAlibegić can you update youy code to latest versions?!Unobtrusive
@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?Wight
@AnisAlibegić stranger, really opening on anonym window not has content. You can see here: gist.github.com/felipecastrosales/…. . I think that this is a bug.Unobtrusive
S
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'),
     );
   }
 }
Sancho answered 18/8, 2019 at 4:52 Comment(1)
Why use help-methods in this case?Unobtrusive

© 2022 - 2024 — McMap. All rights reserved.