diff --git a/packages/flutter/lib/src/gestures/binding.dart b/packages/flutter/lib/src/gestures/binding.dart index 608cb54c1c..6d8c98bd0b 100644 --- a/packages/flutter/lib/src/gestures/binding.dart +++ b/packages/flutter/lib/src/gestures/binding.dart @@ -82,8 +82,8 @@ abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestabl /// binding. The 'event' argument is the pointer event that was being routed. /// The 'target' argument is the class whose handleEvent function threw the /// exception. The 'exception' argument contains the object that was thrown, - /// and the 'stack' argument contains the stack trace. The callback is invoked - /// after the information is printed to the console. + /// and the 'stack' argument contains the stack trace. If no handler is + /// registered, then the information will be printed to the console instead. GesturerExceptionHandler debugGesturerExceptionHandler; /// Dispatch the given event to the path of the given hit test result @@ -93,17 +93,20 @@ abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestabl try { entry.target.handleEvent(event, entry); } catch (exception, stack) { - debugPrint('-- EXCEPTION --'); - debugPrint('The following exception was raised while dispatching a pointer event:'); - debugPrint('$exception'); - debugPrint('Stack trace:'); - debugPrint('$stack'); - debugPrint('Event:'); - debugPrint('$event'); - debugPrint('Target:'); - debugPrint('${entry.target}'); - if (debugGesturerExceptionHandler != null) + if (debugGesturerExceptionHandler != null) { debugGesturerExceptionHandler(event, entry.target, exception, stack); + } else { + debugPrint('-- EXCEPTION CAUGHT BY GESTURE LIBRARY ---------------------------------'); + debugPrint('The following exception was raised while dispatching a pointer event:'); + debugPrint('$exception'); + debugPrint('Event:'); + debugPrint('$event'); + debugPrint('Target:'); + debugPrint('${entry.target}'); + debugPrint('Stack trace:'); + debugPrint('$stack'); + debugPrint('------------------------------------------------------------------------'); + } } } } diff --git a/packages/flutter/lib/src/gestures/pointer_router.dart b/packages/flutter/lib/src/gestures/pointer_router.dart index bea6eb65e4..32fff2e708 100644 --- a/packages/flutter/lib/src/gestures/pointer_router.dart +++ b/packages/flutter/lib/src/gestures/pointer_router.dart @@ -43,9 +43,9 @@ class PointerRouter { /// the exception. The 'event' argument is the pointer event that was being /// routed. The 'route' argument is the callback that threw the exception. The /// 'exception' argument contains the object that was thrown, and the 'stack' - /// argument contains the stack trace. The callback is invoked after the - /// information (exception, stack trace, and event; not the route callback - /// itself) is printed to the console. + /// argument contains the stack trace. If no handler is registered, then the + /// human-readable parts of this information (the exception, event, and stack + /// trace) will be printed to the console instead. PointerExceptionHandler debugPointerExceptionHandler; /// Calls the routes registered for this pointer event. @@ -60,15 +60,18 @@ class PointerRouter { try { route(event); } catch (exception, stack) { - debugPrint('-- EXCEPTION --'); - debugPrint('The following exception was raised while routing a pointer event:'); - debugPrint('$exception'); - debugPrint('Stack trace:'); - debugPrint('$stack'); - debugPrint('Event:'); - debugPrint('$event'); - if (debugPointerExceptionHandler != null) + if (debugPointerExceptionHandler != null) { debugPointerExceptionHandler(this, event, route, exception, stack); + } else { + debugPrint('-- EXCEPTION CAUGHT BY GESTURE LIBRARY ---------------------------------'); + debugPrint('The following exception was raised while routing a pointer event:'); + debugPrint('$exception'); + debugPrint('Event:'); + debugPrint('$event'); + debugPrint('Stack trace:'); + debugPrint('$stack'); + debugPrint('------------------------------------------------------------------------'); + } } } } diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index 888e4f8b39..ca5fd39edd 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -381,9 +381,8 @@ typedef void RenderingExceptionHandler(RenderObject source, String method, dynam /// exception. The 'method' argument is the method in which the exception /// occurred; it will be one of 'performResize', 'performLayout, or 'paint'. The /// 'exception' argument contains the object that was thrown, and the 'stack' -/// argument contains the stack trace. The callback is invoked after the -/// information is printed to the console, and could be used to print additional -/// information, such as from [debugDumpRenderTree()]. +/// argument contains the stack trace. If no handler is registered, then the +/// information will be printed to the console instead. RenderingExceptionHandler debugRenderingExceptionHandler; /// An object in the render tree. @@ -461,16 +460,19 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget { dynamic debugOwner; void _debugReportException(String method, dynamic exception, StackTrace stack) { - debugPrint('-- EXCEPTION --'); - debugPrint('The following exception was raised during $method():'); - debugPrint('$exception'); - debugPrint('Stack trace:'); - debugPrint('$stack'); - debugPrint('The following RenderObject was being processed when the exception was fired:\n${this}'); - if (debugOwner != null) - debugPrint('That RenderObject had the following owner:\n$debugOwner'); - if (debugRenderingExceptionHandler != null) + if (debugRenderingExceptionHandler != null) { debugRenderingExceptionHandler(this, method, exception, stack); + } else { + debugPrint('-- EXCEPTION CAUGHT BY RENDERING LIBRARY -------------------------------'); + debugPrint('The following exception was raised during $method():'); + debugPrint('$exception'); + debugPrint('The following RenderObject was being processed when the exception was fired:\n${this}'); + if (debugOwner != null) + debugPrint('That RenderObject had the following owner:\n$debugOwner'); + debugPrint('Stack trace:'); + debugPrint('$stack'); + debugPrint('------------------------------------------------------------------------'); + } } static bool _debugDoingLayout = false; diff --git a/packages/flutter/lib/src/scheduler/scheduler.dart b/packages/flutter/lib/src/scheduler/scheduler.dart index acfb3e0ee4..3f2107d4ec 100644 --- a/packages/flutter/lib/src/scheduler/scheduler.dart +++ b/packages/flutter/lib/src/scheduler/scheduler.dart @@ -271,10 +271,12 @@ abstract class Scheduler extends BindingBase { if (debugSchedulerExceptionHandler != null) { debugSchedulerExceptionHandler(exception, stack); } else { - print('-- EXCEPTION IN SCHEDULER CALLBACK --'); - print('$exception'); - print('Stack trace:'); - print('$stack'); + debugPrint('-- EXCEPTION CAUGHT BY SCHEDULER LIBRARY -------------------------------'); + debugPrint('An exception was raised during a scheduler callback:'); + debugPrint('$exception'); + debugPrint('Stack trace:'); + debugPrint('$stack'); + debugPrint('------------------------------------------------------------------------'); } } } diff --git a/packages/flutter/lib/src/services/image_resource.dart b/packages/flutter/lib/src/services/image_resource.dart index 0ac5e2f1cf..9732f3b0bb 100644 --- a/packages/flutter/lib/src/services/image_resource.dart +++ b/packages/flutter/lib/src/services/image_resource.dart @@ -5,6 +5,8 @@ import 'dart:async'; import 'dart:ui' as ui; +import 'print.dart'; + /// A callback for when the image is available. typedef void ImageListener(ui.Image image); @@ -15,7 +17,7 @@ typedef void ImageListener(ui.Image image); /// or because the underlying image resource was mutated. class ImageResource { ImageResource(this._futureImage) { - _futureImage.then(_handleImageLoaded, onError: _handleImageError); + _futureImage.then(_handleImageLoaded, onError: (exception, stack) => _handleImageError('Failed to load image:', exception, stack)); } bool _resolved = false; @@ -34,8 +36,13 @@ class ImageResource { /// this object will call the listener synchronously. void addListener(ImageListener listener) { _listeners.add(listener); - if (_resolved) - listener(_image); + if (_resolved) { + try { + listener(_image); + } catch (exception, stack) { + _handleImageError('The following exception was thrown by a synchronously-invoked image listener:', exception, stack); + } + } } /// Stop listening for new concrete [ui.Image] objects. @@ -49,19 +56,24 @@ class ImageResource { _notifyListeners(); } - void _handleImageError(e, stackTrace) { - print('Failed to load image: $e\nStack trace: $stackTrace'); - } - void _notifyListeners() { assert(_resolved); List localListeners = new List.from(_listeners); for (ImageListener listener in localListeners) { try { listener(_image); - } catch(e) { - print('Image listener had exception: $e'); + } catch (exception, stack) { + _handleImageError('The following exception was thrown by an image listener:', exception, stack); } } } + + void _handleImageError(String message, dynamic exception, dynamic stack) { + debugPrint('-- EXCEPTION CAUGHT BY SERVICES LIBRARY --------------------------------'); + debugPrint(message); + debugPrint('$exception'); + debugPrint('Stack trace:'); + debugPrint('$stack'); + debugPrint('------------------------------------------------------------------------'); + } } diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index a401b01ed8..41fe02b2a8 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -1404,6 +1404,7 @@ abstract class RenderObjectElement extends Buildab void mount(Element parent, dynamic newSlot) { super.mount(parent, newSlot); assert(_slot == newSlot); + assert(() { debugUpdateRenderObjectOwner(); return true; }); attachRenderObject(newSlot); _dirty = false; } @@ -1788,7 +1789,7 @@ void _debugReportException(String context, dynamic exception, StackTrace stack) if (debugWidgetsExceptionHandler != null) { debugWidgetsExceptionHandler(context, exception, stack); } else { - debugPrint('------------------------------------------------------------------------'); + debugPrint('-- EXCEPTION CAUGHT BY WIDGETS LIBRARY ---------------------------------'); debugPrint('Exception caught while $context'); debugPrint('$exception'); debugPrint('Stack trace:');