教你如何自定义Flutter错误页面

栏目: IOS · Android · 发布时间: 5年前

内容简介:开发Flutter的时候,肯定都会遇到Flutter错误页面,可以让我们在开发的时候很清楚的知道代码有异常,但是,如果发布出去的APP出现了异常,那么这个错误页面就很不友好,其实这个错误页面是可以自定义的,本篇文章告诉你如何自定义错误页面!这是我们经常看到的错误页面:要想Flutter的错误页面显示成自定义的页面,只要设置

开发Flutter的时候,肯定都会遇到Flutter错误页面,可以让我们在开发的时候很清楚的知道代码有异常,但是,如果发布出去的APP出现了异常,那么这个错误页面就很不友好,其实这个错误页面是可以自定义的,本篇文章告诉你如何自定义错误页面!

0x01 Flutter错误页面

这是我们经常看到的错误页面:

教你如何自定义Flutter错误页面

0x02 自定义Flutter错误页面

要想Flutter的错误页面显示成自定义的页面,只要设置 ErrorWidgetbuilder 就行。 代码如下:

ErrorWidget.builder = (FlutterErrorDetails flutterErrorDetails){
        print(flutterErrorDetails.toString());
        return Center(
          child: Text("Flutter 走神了"),
          );
    };
复制代码

ErrorWidget.builder 返回一个Widget,当Flutter出错的时候就会显示这个Widget, 下图就是我们自定义的错误页面,比Flutter的友好多了:

教你如何自定义Flutter错误页面

0x03 github

本篇文章所涉及的代码: github.com/koudle/GDG_…

github地址: github.com/koudle/GDG_…

0x04 ErrorWidget源码分析

ErrorWidget 的源码在 framework.dart 的3581行-3630行,很简单, ErrorWidget 的构造函数的参数是exception的对象,然后返回一个内容是exception message信息的RenderBox,我们看到的Flutter的错误页面就是这个RenderBox。

class ErrorWidget extends LeafRenderObjectWidget {
  /// 创建一个显示error message的Widget,exception是构造函数的参数。
  ErrorWidget(Object exception) : message = _stringify(exception),
      super(key: UniqueKey());

  //ErrorWidgetBuilder.builder的默认设置是ErrorWidget,我们可以设置成自己的
  static ErrorWidgetBuilder builder = (FlutterErrorDetails details) => ErrorWidget(details.exception);

  /// The message to display.
  final String message;

  //将exception对象转换成string
  static String _stringify(Object exception) {
    try {
      return exception.toString();
    } catch (e) { } // ignore: empty_catches
    return 'Error';
  }
  
  //返回一个内容是exception message信息的RenderBox
  @override
  RenderBox createRenderObject(BuildContext context) => RenderErrorBox(message);

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(StringProperty('message', message, quoted: false));
  }
}
复制代码

0x05 调用ErrorWidget的源码分析

前面看了 ErrorWidget 的源码,只是创建一个Widget,那么是哪里调用 ErrorWidget 显示的呢? 调用 ErrorWidget 的代码总共有三处,这三处都有一个共同点,就是在build Widget的过程中,如果出现异常,则返回一个ErrorWidget显示,具体的源码如下:

  1. ComponentElement(framework.dart)
@override
  void performRebuild() {
    assert(() {
      if (debugProfileBuildsEnabled)
        Timeline.startSync('${widget.runtimeType}',  arguments: timelineWhitelistArguments);
      return true;
    }());

    assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(true));
    Widget built;
    try {
      built = build();
      debugWidgetBuilderValue(widget, built);
    } catch (e, stack) {
      built = ErrorWidget.builder(_debugReportException('building $this', e, stack));
    } finally {
      // We delay marking the element as clean until after calling build() so
      // that attempts to markNeedsBuild() during build() will be ignored.
      _dirty = false;
      assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(false));
    }
    try {
      _child = updateChild(_child, built, slot);
      assert(_child != null);
    } catch (e, stack) {
      built = ErrorWidget.builder(_debugReportException('building $this', e, stack));
      _child = updateChild(null, built, slot);
    }

    assert(() {
      if (debugProfileBuildsEnabled)
        Timeline.finishSync();
      return true;
    }());
  }
复制代码
  1. RenderObjectToWidgetElement(binding.dart)
void _rebuild() {
    try {
      _child = updateChild(_child, widget.child, _rootChildSlot);
      assert(_child != null);
    } catch (exception, stack) {
      final FlutterErrorDetails details = FlutterErrorDetails(
        exception: exception,
        stack: stack,
        library: 'widgets library',
        context: 'attaching to the render tree'
      );
      FlutterError.reportError(details);
      final Widget error = ErrorWidget.builder(details);
      _child = updateChild(null, error, _rootChildSlot);
    }
  }
复制代码
  1. _LayoutBuilderElement (layout_builder.dart)
void _layout(BoxConstraints constraints) {
    owner.buildScope(this, () {
      Widget built;
      if (widget.builder != null) {
        try {
          built = widget.builder(this, constraints);
          debugWidgetBuilderValue(widget, built);
        } catch (e, stack) {
          built = ErrorWidget.builder(_debugReportException('building $widget', e, stack));
        }
      }
      try {
        _child = updateChild(_child, built, null);
        assert(_child != null);
      } catch (e, stack) {
        built = ErrorWidget.builder(_debugReportException('building $widget', e, stack));
        _child = updateChild(null, built, slot);
      }
    });
  }
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

SEM修炼手册:百度竞价、信息流广告、数据分析与专题页策划实战详解

SEM修炼手册:百度竞价、信息流广告、数据分析与专题页策划实战详解

陈丰洲 / 电子工业出版社 / 2018-10 / 59.80元

SEM人员在职场打拼的过程中,会遇到一个又一个坑,《SEM修炼手册:百度竞价、信息流广告、数据分析与专题页策划实战详解》尝试站在一定的高度,将从业者从专员走向管理岗位过程中可能碰到的问题进行整理,不仅谈竞价推广,也谈基于SEM的营销体系。 《SEM修炼手册:百度竞价、信息流广告、数据分析与专题页策划实战详解》包括11章内容,由浅入深地分享SEM的进阶过程。第1章是SEM概述,让读者对SEM有......一起来看看 《SEM修炼手册:百度竞价、信息流广告、数据分析与专题页策划实战详解》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具