Commit 2b343a93 authored by Ian Hickson's avatar Ian Hickson Committed by John McCutchan

Some cleanup for hot reload (#5108)

- show the next error fully after a hot reload
- hide _AssertionError in stacks
- immediately rebuild after a reassemble, so that hit tests work
- catch errors when notifying global key listeners
parent db8ff48d
...@@ -153,6 +153,14 @@ class FlutterError extends AssertionError { ...@@ -153,6 +153,14 @@ class FlutterError extends AssertionError {
static int _errorCount = 0; static int _errorCount = 0;
/// Resets the count of errors used by [dumpErrorToConsole] to decide whether
/// to show a complete error message or an abbreviated one.
///
/// After this is called, the next error message will be shown in full.
static void resetErrorCount() {
_errorCount = 0;
}
static const int _kWrapWidth = 100; static const int _kWrapWidth = 100;
/// Prints the given exception details to the console. /// Prints the given exception details to the console.
...@@ -163,6 +171,9 @@ class FlutterError extends AssertionError { ...@@ -163,6 +171,9 @@ class FlutterError extends AssertionError {
/// Subsequent calls only dump the first line of the exception, unless /// Subsequent calls only dump the first line of the exception, unless
/// `forceReport` is set to true (in which case it dumps the verbose message). /// `forceReport` is set to true (in which case it dumps the verbose message).
/// ///
/// Call [resetErrorCount] to cause this method to go back to acting as if it
/// had not been called before (so the next message is verbose again).
///
/// The default behavior for the [onError] handler is to call this function. /// The default behavior for the [onError] handler is to call this function.
static void dumpErrorToConsole(FlutterErrorDetails details, { bool forceReport: false }) { static void dumpErrorToConsole(FlutterErrorDetails details, { bool forceReport: false }) {
assert(details != null); assert(details != null);
...@@ -258,17 +269,18 @@ class FlutterError extends AssertionError { ...@@ -258,17 +269,18 @@ class FlutterError extends AssertionError {
/// format but the frame numbers will not be consecutive (frames are elided) /// format but the frame numbers will not be consecutive (frames are elided)
/// and the final line may be prose rather than a stack frame. /// and the final line may be prose rather than a stack frame.
static Iterable<String> defaultStackFilter(Iterable<String> frames) { static Iterable<String> defaultStackFilter(Iterable<String> frames) {
final List<String> result = <String>[]; const List<String> filteredPackages = const <String>[
final List<String> filteredPackages = <String>[
'dart:async-patch', 'dart:async-patch',
'dart:async', 'dart:async',
'package:stack_trace', 'package:stack_trace',
]; ];
final List<String> filteredClasses = <String>[ const List<String> filteredClasses = const <String>[
'_AssertionError',
'_FakeAsync', '_FakeAsync',
]; ];
final RegExp stackParser = new RegExp(r'^#[0-9]+ +([^.]+).* \(([^/]*)/[^:]+:[0-9]+(?::[0-9]+)?\)$'); final RegExp stackParser = new RegExp(r'^#[0-9]+ +([^.]+).* \(([^/]*)/[^:]+:[0-9]+(?::[0-9]+)?\)$');
final RegExp packageParser = new RegExp(r'^([^:]+):(.+)$'); final RegExp packageParser = new RegExp(r'^([^:]+):(.+)$');
final List<String> result = <String>[];
final List<String> skipped = <String>[]; final List<String> skipped = <String>[];
for (String line in frames) { for (String line in frames) {
Match match = stackParser.firstMatch(line); Match match = stackParser.firstMatch(line);
......
...@@ -119,7 +119,10 @@ abstract class BindingBase { ...@@ -119,7 +119,10 @@ abstract class BindingBase {
/// that uses closures, so that they do not keep pointing to old /// that uses closures, so that they do not keep pointing to old
/// code, and to flush any caches of previously computed values, in /// code, and to flush any caches of previously computed values, in
/// case the new code would compute them differently. /// case the new code would compute them differently.
void reassembleApplication() { } @mustCallSuper
void reassembleApplication() {
FlutterError.resetErrorCount();
}
/// Registers a service extension method with the given name (full /// Registers a service extension method with the given name (full
/// name "ext.flutter.name"), which takes no arguments and returns /// name "ext.flutter.name"), which takes no arguments and returns
......
...@@ -165,6 +165,7 @@ abstract class RendererBinding extends BindingBase implements SchedulerBinding, ...@@ -165,6 +165,7 @@ abstract class RendererBinding extends BindingBase implements SchedulerBinding,
void reassembleApplication() { void reassembleApplication() {
super.reassembleApplication(); super.reassembleApplication();
pipelineOwner.reassemble(); pipelineOwner.reassemble();
beginFrame();
} }
@override @override
......
...@@ -429,7 +429,7 @@ abstract class SchedulerBinding extends BindingBase { ...@@ -429,7 +429,7 @@ abstract class SchedulerBinding extends BindingBase {
Duration timeStamp = _adjustForEpoch(rawTimeStamp); Duration timeStamp = _adjustForEpoch(rawTimeStamp);
assert(() { assert(() {
if (debugPrintBeginFrameBanner) if (debugPrintBeginFrameBanner)
print('━‬━‬━‬━‬━‬━‬━┫ Begin Frame ($timeStamp) ┣━‬━‬━‬━‬━‬━‬━'); print('━━━━━━━┫ Begin Frame ($timeStamp) ┣━━━━━━━');
return true; return true;
}); });
_lastRawTimeStamp = rawTimeStamp; _lastRawTimeStamp = rawTimeStamp;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'basic.dart'; import 'basic.dart';
......
...@@ -226,6 +226,7 @@ abstract class GlobalKey<T extends State<StatefulWidget>> extends Key { ...@@ -226,6 +226,7 @@ abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
static void unregisterRemoveListener(GlobalKey key, GlobalKeyRemoveListener listener) { static void unregisterRemoveListener(GlobalKey key, GlobalKeyRemoveListener listener) {
assert(key != null); assert(key != null);
assert(_removeListeners.containsKey(key)); assert(_removeListeners.containsKey(key));
assert(_removeListeners[key].contains(listener));
bool removed = _removeListeners[key].remove(listener); bool removed = _removeListeners[key].remove(listener);
if (_removeListeners[key].isEmpty) if (_removeListeners[key].isEmpty)
_removeListeners.remove(key); _removeListeners.remove(key);
...@@ -258,6 +259,8 @@ abstract class GlobalKey<T extends State<StatefulWidget>> extends Key { ...@@ -258,6 +259,8 @@ abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
listener(key); listener(key);
} }
} }
} catch (e, stack) {
_debugReportException('while notifying GlobalKey listeners', e, stack);
} finally { } finally {
_removedKeys.clear(); _removedKeys.clear();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment