Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
c28121ee
Unverified
Commit
c28121ee
authored
Dec 14, 2017
by
Ian Hickson
Committed by
GitHub
Dec 14, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow the ErrorWidget to be overridden. (#13578)
Fixes
https://github.com/flutter/flutter/issues/10695
parent
f9cf5a1f
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
174 additions
and
18 deletions
+174
-18
assertions.dart
packages/flutter/lib/src/foundation/assertions.dart
+32
-0
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+1
-0
binding.dart
packages/flutter/lib/src/widgets/binding.dart
+4
-3
framework.dart
packages/flutter/lib/src/widgets/framework.dart
+50
-7
layout_builder.dart
packages/flutter/lib/src/widgets/layout_builder.dart
+11
-7
assertions_test.dart
packages/flutter/test/foundation/assertions_test.dart
+51
-1
error_widget_builder_test.dart
packages/flutter/test/widgets/error_widget_builder_test.dart
+25
-0
No files found.
packages/flutter/lib/src/foundation/assertions.dart
View file @
c28121ee
...
...
@@ -140,6 +140,38 @@ class FlutterErrorDetails {
longMessage
=
' <no message available>'
;
return
longMessage
;
}
@override
String
toString
()
{
final
StringBuffer
buffer
=
new
StringBuffer
();
if
((
library
!=
null
&&
library
!=
''
)
||
(
context
!=
null
&&
context
!=
''
))
{
if
(
library
!=
null
&&
library
!=
''
)
{
buffer
.
write
(
'Error caught by
$library
'
);
if
(
context
!=
null
&&
context
!=
''
)
buffer
.
write
(
', '
);
}
else
{
buffer
.
writeln
(
'Exception '
);
}
if
(
context
!=
null
&&
context
!=
''
)
buffer
.
write
(
'thrown
$context
'
);
buffer
.
writeln
(
'.'
);
}
else
{
buffer
.
write
(
'An error was caught.'
);
}
buffer
.
writeln
(
exceptionAsString
());
if
(
informationCollector
!=
null
)
informationCollector
(
buffer
);
if
(
stack
!=
null
)
{
Iterable
<
String
>
stackLines
=
stack
.
toString
().
trimRight
().
split
(
'
\n
'
);
if
(
stackFilter
!=
null
)
{
stackLines
=
stackFilter
(
stackLines
);
}
else
{
stackLines
=
FlutterError
.
defaultStackFilter
(
stackLines
);
}
buffer
.
writeAll
(
stackLines
,
'
\n
'
);
}
return
buffer
.
toString
().
trimRight
();
}
}
/// Error class used to report Flutter-specific assertion failures and
...
...
packages/flutter/lib/src/widgets/basic.dart
View file @
c28121ee
...
...
@@ -14,6 +14,7 @@ import 'framework.dart';
export
'package:flutter/animation.dart'
;
export
'package:flutter/foundation.dart'
show
ChangeNotifier
,
FlutterErrorDetails
,
Listenable
,
TargetPlatform
,
ValueNotifier
;
...
...
packages/flutter/lib/src/widgets/binding.dart
View file @
c28121ee
...
...
@@ -840,13 +840,14 @@ class RenderObjectToWidgetElement<T extends RenderObject> extends RootRenderObje
_child
=
updateChild
(
_child
,
widget
.
child
,
_rootChildSlot
);
assert
(
_child
!=
null
);
}
catch
(
exception
,
stack
)
{
FlutterError
.
reportError
(
new
FlutterErrorDetails
(
final
FlutterErrorDetails
details
=
new
FlutterErrorDetails
(
exception:
exception
,
stack:
stack
,
library
:
'widgets library'
,
context:
'attaching to the render tree'
));
final
Widget
error
=
new
ErrorWidget
(
exception
);
);
FlutterError
.
reportError
(
details
);
final
Widget
error
=
ErrorWidget
.
builder
(
details
);
_child
=
updateChild
(
null
,
error
,
_rootChildSlot
);
}
}
...
...
packages/flutter/lib/src/widgets/framework.dart
View file @
c28121ee
...
...
@@ -3456,6 +3456,20 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
void
performRebuild
();
}
/// Signature for the constructor that is called when an error occurs while
/// building a widget.
///
/// The argument provides information regarding the cause of the error.
///
/// See also:
///
/// * [ErrorWidget.builder], which can be set to override the default
/// [ErrorWidget] builder.
/// * [FlutterError.reportError], which is typically called with the same
/// [FlutterErrorDetails] object immediately prior to [ErrorWidget.builder]
/// being called.
typedef
Widget
ErrorWidgetBuilder
(
FlutterErrorDetails
details
);
/// A widget that renders an exception's message.
///
/// This widget is used when a build method fails, to help with determining
...
...
@@ -3467,6 +3481,32 @@ class ErrorWidget extends LeafRenderObjectWidget {
ErrorWidget
(
Object
exception
)
:
message
=
_stringify
(
exception
),
super
(
key:
new
UniqueKey
());
/// The configurable factory for [ErrorWidget].
///
/// When an error occurs while building a widget, the broken widget is
/// replaced by the widget returned by this function. By default, an
/// [ErrorWidget] is returned.
///
/// The system is typically in an unstable state when this function is called.
/// An exception has just been thrown in the middle of build (and possibly
/// layout), so surrounding widgets and render objects may be in a rather
/// fragile state. The framework itself (especially the [BuildOwner]) may also
/// be confused, and additional exceptions are quite likely to be thrown.
///
/// Because of this, it is highly recommended that the widget returned from
/// this function perform the least amount of work possible. A
/// [LeafRenderObjectWidget] is the best choice, especially one that
/// corresponds to a [RenderBox] that can handle the most absurd of incoming
/// constraints. The default constructor maps to a [RenderErrorBox].
///
/// See also:
///
/// * [FlutterError.onError], which is typically called with the same
/// [FlutterErrorDetails] object immediately prior to this callback being
/// invoked, and which can also be configured to control how errors are
/// reported.
static
ErrorWidgetBuilder
builder
=
(
FlutterErrorDetails
details
)
=>
new
ErrorWidget
(
details
.
exception
);
/// The message to display.
final
String
message
;
...
...
@@ -3544,8 +3584,7 @@ abstract class ComponentElement extends Element {
built
=
build
();
debugWidgetBuilderValue
(
widget
,
built
);
}
catch
(
e
,
stack
)
{
_debugReportException
(
'building
$this
'
,
e
,
stack
);
built
=
new
ErrorWidget
(
e
);
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.
...
...
@@ -3556,8 +3595,7 @@ abstract class ComponentElement extends Element {
_child
=
updateChild
(
_child
,
built
,
slot
);
assert
(
_child
!=
null
);
}
catch
(
e
,
stack
)
{
_debugReportException
(
'building
$this
'
,
e
,
stack
);
built
=
new
ErrorWidget
(
e
);
built
=
ErrorWidget
.
builder
(
_debugReportException
(
'building
$this
'
,
e
,
stack
));
_child
=
updateChild
(
null
,
built
,
slot
);
}
...
...
@@ -4656,14 +4694,19 @@ class _DebugCreator {
String
toString
()
=>
element
.
debugGetCreatorChain
(
12
);
}
void
_debugReportException
(
String
context
,
dynamic
exception
,
StackTrace
stack
,
{
FlutterErrorDetails
_debugReportException
(
String
context
,
dynamic
exception
,
StackTrace
stack
,
{
InformationCollector
informationCollector
})
{
FlutterError
.
reportError
(
new
FlutterErrorDetails
(
final
FlutterErrorDetails
details
=
new
FlutterErrorDetails
(
exception:
exception
,
stack:
stack
,
library
:
'widgets library'
,
context:
context
,
informationCollector:
informationCollector
,
));
);
FlutterError
.
reportError
(
details
);
return
details
;
}
packages/flutter/lib/src/widgets/layout_builder.dart
View file @
c28121ee
...
...
@@ -111,16 +111,14 @@ class _LayoutBuilderElement extends RenderObjectElement {
built
=
widget
.
builder
(
this
,
constraints
);
debugWidgetBuilderValue
(
widget
,
built
);
}
catch
(
e
,
stack
)
{
_debugReportException
(
'building
$widget
'
,
e
,
stack
);
built
=
new
ErrorWidget
(
e
);
built
=
ErrorWidget
.
builder
(
_debugReportException
(
'building
$widget
'
,
e
,
stack
));
}
}
try
{
_child
=
updateChild
(
_child
,
built
,
null
);
assert
(
_child
!=
null
);
}
catch
(
e
,
stack
)
{
_debugReportException
(
'building
$widget
'
,
e
,
stack
);
built
=
new
ErrorWidget
(
e
);
built
=
ErrorWidget
.
builder
(
_debugReportException
(
'building
$widget
'
,
e
,
stack
));
_child
=
updateChild
(
null
,
built
,
slot
);
}
});
...
...
@@ -225,11 +223,17 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
}
}
void
_debugReportException
(
String
context
,
dynamic
exception
,
StackTrace
stack
)
{
FlutterError
.
reportError
(
new
FlutterErrorDetails
(
FlutterErrorDetails
_debugReportException
(
String
context
,
dynamic
exception
,
StackTrace
stack
,
)
{
final
FlutterErrorDetails
details
=
new
FlutterErrorDetails
(
exception:
exception
,
stack:
stack
,
library
:
'widgets library'
,
context:
context
));
);
FlutterError
.
reportError
(
details
);
return
details
;
}
packages/flutter/test/foundation/assertions_test.dart
View file @
c28121ee
...
...
@@ -16,7 +16,6 @@ void main() {
expect
(
log
[
1
],
contains
(
'debugPrintStack'
));
});
test
(
'debugPrintStack'
,
()
{
final
List
<
String
>
log
=
captureOutput
(()
{
final
FlutterErrorDetails
details
=
new
FlutterErrorDetails
(
...
...
@@ -42,4 +41,55 @@ void main() {
expect
(
joined
,
contains
(
'
\n
Example information
\n
'
));
});
test
(
'FlutterErrorDetails.toString'
,
()
{
expect
(
new
FlutterErrorDetails
(
exception:
'MESSAGE'
,
library
:
'LIBRARY'
,
context:
'CONTEXTING'
,
informationCollector:
(
StringBuffer
information
)
{
information
.
writeln
(
'INFO'
);
},
).
toString
(),
'Error caught by LIBRARY, thrown CONTEXTING.
\n
'
'MESSAGE
\n
'
'INFO'
,
);
expect
(
new
FlutterErrorDetails
(
library
:
'LIBRARY'
,
context:
'CONTEXTING'
,
informationCollector:
(
StringBuffer
information
)
{
information
.
writeln
(
'INFO'
);
},
).
toString
(),
'Error caught by LIBRARY, thrown CONTEXTING.
\n
'
' null
\n
'
'INFO'
,
);
expect
(
new
FlutterErrorDetails
(
exception:
'MESSAGE'
,
context:
'CONTEXTING'
,
informationCollector:
(
StringBuffer
information
)
{
information
.
writeln
(
'INFO'
);
},
).
toString
(),
'Error caught by Flutter framework, thrown CONTEXTING.
\n
'
'MESSAGE
\n
'
'INFO'
,
);
expect
(
const
FlutterErrorDetails
(
exception:
'MESSAGE'
,
).
toString
(),
'Error caught by Flutter framework.
\n
'
'MESSAGE'
);
expect
(
const
FlutterErrorDetails
().
toString
(),
'Error caught by Flutter framework.
\n
'
' null'
);
});
}
packages/flutter/test/widgets/error_widget_builder_test.dart
0 → 100644
View file @
c28121ee
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/widgets.dart'
;
void
main
(
)
{
testWidgets
(
'ErrorWidget.builder'
,
(
WidgetTester
tester
)
async
{
ErrorWidget
.
builder
=
(
FlutterErrorDetails
details
)
{
return
const
Text
(
'oopsie!'
,
textDirection:
TextDirection
.
ltr
);
};
await
tester
.
pumpWidget
(
new
SizedBox
(
child:
new
Builder
(
builder:
(
BuildContext
context
)
{
throw
'test'
;
},
),
),
);
expect
(
tester
.
takeException
().
toString
(),
'test'
);
expect
(
find
.
text
(
'oopsie!'
),
findsOneWidget
);
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment