Flutter App开发:错误页面定制教程
在开发Flutter时,肯定会遇到Flutter错误页面,它可以让我们清楚地知道开发时代码中存在异常。但是,如果发布的APP出现异常,那么这个错误页面就非常不友好了。事实上,这个错误页面是可以定制的。本文告诉你如何自定义错误页面!
0x01 Flutter错误页面
这是我们经常看到的错误页面:
0x02自定义Flutter错误页面
如果你想让Flutter错误页面显示为自定义页面,只需设置❀错误 的 Builder
就可以了。代码如下:
ErrorWidget.builder = (FlutterErrorDetails flutterErrorDetails){
print(flutterErrorDetails.toString());
return Center(
child: Text("Flutter 走神了"),
);
};
复制代码
ErrorWidget.builder
返回一个当 Flutter 遇到错误时将显示的 widget。下图是我们自定义的错误页面,比Flutter的友好多了:
0x03 github
本文涉及的代码:github.com/koudle/GDG_…
github地址:github.com/koudle /GDG_…
0x04 ErrorWidget源码分析
ErrorWidget
ErrorWidget
的构造函数参数为异常对象,然后返回一个内容为异常消息信息的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
。这三个地方有一个共同点,就是在构建widget的过程中,如果出现异常,就会返回ErrorWidget显示。具体源码如下:
- 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;
}());
}
复制代码
- 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);
}
}
复制代码
- _LayoutBuilderElement(layout_builder.dart) oEN:A 链接:https://juejin.im/ post /5c3f1cf66fb9a049d519c 4cb
来源:掘金
版权属于作者。如需商业转载,请联系求作者授权。非商业转载请来源。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。