Clean up the bindings APIs (#86438)

This commit is contained in:
Ian Hickson 2021-07-14 14:41:24 -07:00 committed by GitHub
parent 666185c027
commit d056500bfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
249 changed files with 1637 additions and 1271 deletions

View File

@ -32,7 +32,7 @@ Future<void> main() async {
child: ComplexLayoutApp(),
),
));
await SchedulerBinding.instance?.endOfFrame;
await SchedulerBinding.instance.endOfFrame;
/// Wait 50ms to allow the raster thread to actually put up the frame. (The
/// endOfFrame future ends when we send the data to the engine, before
@ -50,9 +50,9 @@ Future<void> main() async {
child: ComplexLayoutApp(),
),
));
await SchedulerBinding.instance?.endOfFrame;
await SchedulerBinding.instance.endOfFrame;
final WidgetController controller = LiveWidgetController(WidgetsBinding.instance!);
final WidgetController controller = LiveWidgetController(WidgetsBinding.instance);
// Scroll down
for (int iteration = 0; iteration < maxIterations; iteration += 1) {

View File

@ -41,7 +41,7 @@ class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
_filterType = widget.initialFilterType;
_complexChild = widget.initialComplexChild;
_useRepaintBoundary = widget.initialUseRepaintBoundary;
WidgetsBinding.instance!.addPostFrameCallback((_) {
WidgetsBinding.instance.addPostFrameCallback((_) {
final RenderBox childBox = _childKey.currentContext!.findRenderObject()! as RenderBox;
_childCenter = childBox.paintBounds.center;
});

View File

@ -11,7 +11,7 @@ class LargeImagesPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final ImageCache imageCache = PaintingBinding.instance!.imageCache!;
final ImageCache imageCache = PaintingBinding.instance.imageCache;
imageCache.maximumSize = 30;
imageCache.maximumSizeBytes = 50 << 20;
return GridView.builder(

View File

@ -66,7 +66,7 @@ class BenchMouseRegionGridHover extends WidgetRecorder {
void frameDidDraw() {
if (!started) {
started = true;
SchedulerBinding.instance!.addPostFrameCallback((Duration timeStamp) async {
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) async {
_tester.start();
registerDidStop(_tester.stop);
});
@ -124,7 +124,7 @@ class _UntilNextFrame {
static Future<void> wait() {
if (_UntilNextFrame._completer == null) {
_UntilNextFrame._completer = Completer<void>();
SchedulerBinding.instance!.addPostFrameCallback((_) {
SchedulerBinding.instance.addPostFrameCallback((_) {
_UntilNextFrame._completer!.complete(null);
_UntilNextFrame._completer = null;
});
@ -145,7 +145,7 @@ class _Tester {
TestGesture get gesture {
return _gesture ??= TestGesture(
dispatcher: (PointerEvent event) async {
RendererBinding.instance!.handlePointerEvent(event);
RendererBinding.instance.handlePointerEvent(event);
},
kind: PointerDeviceKind.mouse,
);

View File

@ -41,7 +41,7 @@ class BenchMouseRegionGridScroll extends WidgetRecorder {
void frameDidDraw() {
if (!started) {
started = true;
SchedulerBinding.instance!.addPostFrameCallback((Duration timeStamp) async {
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) async {
_tester.start();
registerDidStop(_tester.stop);
});
@ -96,7 +96,7 @@ class _UntilNextFrame {
static Future<void> wait() {
if (_UntilNextFrame._completer == null) {
_UntilNextFrame._completer = Completer<void>();
SchedulerBinding.instance!.addPostFrameCallback((_) {
SchedulerBinding.instance.addPostFrameCallback((_) {
_UntilNextFrame._completer!.complete(null);
_UntilNextFrame._completer = null;
});
@ -117,7 +117,7 @@ class _Tester {
TestGesture get gesture {
return _gesture ??= TestGesture(
dispatcher: (PointerEvent event) async {
RendererBinding.instance!.handlePointerEvent(event);
RendererBinding.instance.handlePointerEvent(event);
},
kind: PointerDeviceKind.mouse,
);

View File

@ -85,7 +85,7 @@ class BenchMouseRegionMixedGridHover extends WidgetRecorder {
void frameDidDraw() {
if (!started) {
started = true;
SchedulerBinding.instance!.addPostFrameCallback((Duration timeStamp) async {
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) async {
_tester.start();
registerDidStop(_tester.stop);
});
@ -146,7 +146,7 @@ class _UntilNextFrame {
static Future<void> wait() {
if (_UntilNextFrame._completer == null) {
_UntilNextFrame._completer = Completer<void>();
SchedulerBinding.instance!.addPostFrameCallback((_) {
SchedulerBinding.instance.addPostFrameCallback((_) {
_UntilNextFrame._completer!.complete(null);
_UntilNextFrame._completer = null;
});
@ -167,7 +167,7 @@ class _Tester {
TestGesture get gesture {
return _gesture ??= TestGesture(
dispatcher: (PointerEvent event) async {
RendererBinding.instance!.handlePointerEvent(event);
RendererBinding.instance.handlePointerEvent(event);
},
kind: PointerDeviceKind.mouse,
);

View File

@ -935,7 +935,7 @@ double _computeAverage(String label, Iterable<double> values) {
///
/// See also:
///
/// * https://en.wikipedia.org/wiki/Standard_deviation
/// * <https://en.wikipedia.org/wiki/Standard_deviation>
double _computeStandardDeviationForPopulation(String label, Iterable<double> population) {
if (population.isEmpty) {
throw StateError('$label: attempted to compute the standard deviation of empty population.');
@ -987,12 +987,32 @@ class _RecordingWidgetsBinding extends BindingBase
SemanticsBinding,
RendererBinding,
WidgetsBinding {
/// Makes an instance of [_RecordingWidgetsBinding] the current binding.
@override
void initInstances() {
super.initInstances();
_instance = this;
}
/// The singleton instance of this object.
///
/// Provides access to the features exposed by this class. The binding must
/// be initialized before using this getter; this is typically done by calling
/// [_RecordingWidgetsBinding.ensureInitialized].
static _RecordingWidgetsBinding get instance => BindingBase.checkInstance(_instance);
static _RecordingWidgetsBinding? _instance;
/// Returns an instance of the [_RecordingWidgetsBinding], creating and
/// initializing it if necessary.
///
/// See also:
///
/// * [WidgetsFlutterBinding.ensureInitialized], the equivalent in the widgets framework.
static _RecordingWidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null) {
if (_instance == null) {
_RecordingWidgetsBinding();
}
return WidgetsBinding.instance! as _RecordingWidgetsBinding;
return instance;
}
FrameRecorder? _recorder;

View File

@ -10,8 +10,7 @@ import 'package:integration_test/integration_test.dart';
import 'package:macrobenchmarks/src/simple_scroll.dart';
void main() {
final IntegrationTestWidgetsFlutterBinding binding =
IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets(
'Frame Counter and Input Delay for benchmarkLive',
(WidgetTester tester) async {

View File

@ -10,8 +10,8 @@ import 'package:macrobenchmarks/main.dart';
Future<void> endOfAnimation() async {
do {
await SchedulerBinding.instance!.endOfFrame;
} while (SchedulerBinding.instance!.hasScheduledFrame);
await SchedulerBinding.instance.endOfFrame;
} while (SchedulerBinding.instance.hasScheduledFrame);
}
Future<void> main() async {

View File

@ -10,8 +10,8 @@ import 'package:macrobenchmarks/main.dart';
Future<void> endOfAnimation() async {
do {
await SchedulerBinding.instance!.endOfFrame;
} while (SchedulerBinding.instance!.hasScheduledFrame);
await SchedulerBinding.instance.endOfFrame;
} while (SchedulerBinding.instance.hasScheduledFrame);
}
Future<void> main() async {

View File

@ -44,24 +44,24 @@ Future<void> main() async {
// Wait for frame rendering to stabilize.
for (int i = 0; i < 5; i++) {
await SchedulerBinding.instance?.endOfFrame;
await SchedulerBinding.instance.endOfFrame;
}
final Stopwatch watch = Stopwatch();
print('flutter_test allElements benchmark... (${WidgetsBinding.instance?.renderViewElement})');
print('flutter_test allElements benchmark... (${WidgetsBinding.instance.renderViewElement})');
// Make sure we get enough elements to process for consistent benchmark runs
int elementCount = collectAllElementsFrom(WidgetsBinding.instance!.renderViewElement!, skipOffstage: false).length;
int elementCount = collectAllElementsFrom(WidgetsBinding.instance.renderViewElement!, skipOffstage: false).length;
while (elementCount < 2458) {
await Future<void>.delayed(Duration.zero);
elementCount = collectAllElementsFrom(WidgetsBinding.instance!.renderViewElement!, skipOffstage: false).length;
elementCount = collectAllElementsFrom(WidgetsBinding.instance.renderViewElement!, skipOffstage: false).length;
}
print('element count: $elementCount');
watch.start();
for (int i = 0; i < _kNumIters; i += 1) {
final List<Element> allElements = collectAllElementsFrom(
WidgetsBinding.instance!.renderViewElement!,
WidgetsBinding.instance.renderViewElement!,
skipOffstage: false,
).toList();
allElements.clear();

View File

@ -68,7 +68,7 @@ Future<void> main() async {
// Time how long each frame takes
cpuWatch.reset();
while (SchedulerBinding.instance!.hasScheduledFrame) {
while (SchedulerBinding.instance.hasScheduledFrame) {
await tester.pump();
totalSubsequentFramesIterationCount += 1;
}

View File

@ -33,18 +33,18 @@ Future<void> main() async {
final TestViewConfiguration big = TestViewConfiguration(
size: const Size(360.0, 640.0),
window: RendererBinding.instance?.window,
window: RendererBinding.instance.window,
);
final TestViewConfiguration small = TestViewConfiguration(
size: const Size(355.0, 635.0),
window: RendererBinding.instance?.window,
window: RendererBinding.instance.window,
);
final RenderView? renderView = WidgetsBinding.instance?.renderView;
final RenderView renderView = WidgetsBinding.instance.renderView;
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmark;
watch.start();
while (watch.elapsed < kBenchmarkTime) {
renderView?.configuration = iterations.isEven ? big : small;
renderView.configuration = iterations.isEven ? big : small;
await tester.pumpBenchmark(Duration(milliseconds: iterations * 16));
iterations += 1;
}

View File

@ -42,7 +42,7 @@ class _HomePage extends State<HomePage> {
// Trigger the second route.
// https://github.com/flutter/flutter/issues/40126
WidgetsBinding.instance?.addPostFrameCallback((_) async {
WidgetsBinding.instance.addPostFrameCallback((_) async {
Navigator.of(context).push(
MaterialPageRoute<void>(builder: (_) => const SecondPage()));
});

View File

@ -7,7 +7,7 @@ import 'package:flutter_gallery/demo/calculator_demo.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;

View File

@ -8,7 +8,7 @@ import 'package:flutter_gallery/gallery/app.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;

View File

@ -7,7 +7,7 @@ import 'package:flutter_gallery/gallery/app.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;

View File

@ -58,7 +58,7 @@ Future<void> main() async {
print('Starting app...');
runApp(const GalleryApp(testMode: true));
final _LiveWidgetController controller = _LiveWidgetController(WidgetsBinding.instance!);
final _LiveWidgetController controller = _LiveWidgetController(WidgetsBinding.instance);
for (final GalleryDemoCategory category in kAllGalleryDemoCategories) {
print('Tapping "${category.name}" section...');
await controller.tap(find.text(category.name));
@ -111,7 +111,7 @@ class _LiveWidgetController extends LiveWidgetController {
Future<void> _waitUntilFrame(bool Function() condition, [Completer<void>? completer]) {
completer ??= Completer<void>();
if (!condition()) {
SchedulerBinding.instance!.addPostFrameCallback((Duration timestamp) {
SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
_waitUntilFrame(condition, completer);
});
} else {

View File

@ -7,7 +7,7 @@ import 'package:flutter_gallery/gallery/app.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;

View File

@ -7,7 +7,7 @@ import 'package:flutter_gallery/gallery/app.dart' show GalleryApp;
import 'package:flutter_test/flutter_test.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;

View File

@ -77,9 +77,9 @@ Future<void> smokeDemo(WidgetTester tester, GalleryDemo demo) async {
// Verify that the dumps are pretty.
final String routeName = demo.routeName;
verifyToStringOutput('debugDumpApp', routeName, WidgetsBinding.instance!.renderViewElement!.toStringDeep());
verifyToStringOutput('debugDumpRenderTree', routeName, RendererBinding.instance?.renderView.toStringDeep() ?? '');
verifyToStringOutput('debugDumpLayerTree', routeName, RendererBinding.instance?.renderView.debugLayer?.toStringDeep() ?? '');
verifyToStringOutput('debugDumpApp', routeName, WidgetsBinding.instance.renderViewElement!.toStringDeep());
verifyToStringOutput('debugDumpRenderTree', routeName, RendererBinding.instance.renderView.toStringDeep());
verifyToStringOutput('debugDumpLayerTree', routeName, RendererBinding.instance.renderView.debugLayer?.toStringDeep() ?? '');
// Scroll the demo around a bit more.
await tester.flingFrom(const Offset(400.0, 300.0), const Offset(0.0, 400.0), 1000.0);
@ -179,8 +179,8 @@ void main() {
testWidgets('Flutter Gallery app smoke test', smokeGallery);
testWidgets('Flutter Gallery app smoke test with semantics', (WidgetTester tester) async {
RendererBinding.instance!.setSemanticsEnabled(true);
RendererBinding.instance.setSemanticsEnabled(true);
await smokeGallery(tester);
RendererBinding.instance!.setSemanticsEnabled(false);
RendererBinding.instance.setSemanticsEnabled(false);
});
}

View File

@ -11,7 +11,7 @@ Future<String> mockUpdateUrlFetcher() {
}
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;

View File

@ -30,12 +30,12 @@ class _MessageHandler {
case 'demoNames':
return const JsonEncoder.withIndent(' ').convert(_allDemos);
case 'profileDemos':
controller ??= LiveWidgetController(WidgetsBinding.instance!);
controller ??= LiveWidgetController(WidgetsBinding.instance);
await runDemos(kProfiledDemos, controller!);
_unTestedDemos.removeAll(kProfiledDemos);
return const JsonEncoder.withIndent(' ').convert(kProfiledDemos);
case 'restDemos':
controller ??= LiveWidgetController(WidgetsBinding.instance!);
controller ??= LiveWidgetController(WidgetsBinding.instance);
final List<String> restDemos = _unTestedDemos.toList();
await runDemos(restDemos, controller!);
return const JsonEncoder.withIndent(' ').convert(restDemos);

View File

@ -22,8 +22,7 @@ List<String> _allDemos = kAllGalleryDemos.map(
void main([List<String> args = const <String>[]]) {
final bool withSemantics = args.contains('--with_semantics');
final IntegrationTestWidgetsFlutterBinding binding =
IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
group('flutter gallery transitions on e2e', () {
testWidgets('find.bySemanticsLabel', (WidgetTester tester) async {

View File

@ -11,8 +11,8 @@ import 'package:flutter_test/flutter_test.dart';
Future<void> endOfAnimation() async {
do {
await SchedulerBinding.instance!.endOfFrame;
} while (SchedulerBinding.instance!.hasScheduledFrame);
await SchedulerBinding.instance.endOfFrame;
} while (SchedulerBinding.instance.hasScheduledFrame);
}
int iteration = 0;
@ -30,5 +30,5 @@ Future<void> main() async {
await endOfAnimation();
await Future<void>.delayed(const Duration(milliseconds: 50));
debugPrint('==== MEMORY BENCHMARK ==== READY ====');
WidgetsBinding.instance!.addObserver(LifecycleObserver());
WidgetsBinding.instance.addObserver(LifecycleObserver());
}

View File

@ -38,7 +38,7 @@ Future<void> main() async {
),
));
await SchedulerBinding.instance!.endOfFrame;
await SchedulerBinding.instance.endOfFrame;
// We are waiting for the GPU to rasterize a frame here. This makes this
// flaky, we can rely on a more deterministic source such as
@ -48,7 +48,7 @@ Future<void> main() async {
debugPrint('==== MEMORY BENCHMARK ==== READY ====');
final WidgetController controller =
LiveWidgetController(WidgetsBinding.instance!);
LiveWidgetController(WidgetsBinding.instance);
debugPrint('Scrolling...');
final Finder list = find.byKey(const Key('ImageList'));

View File

@ -13,8 +13,8 @@ import 'package:flutter_test/flutter_test.dart';
Future<void> endOfAnimation() async {
do {
await SchedulerBinding.instance!.endOfFrame;
} while (SchedulerBinding.instance!.hasScheduledFrame);
await SchedulerBinding.instance.endOfFrame;
} while (SchedulerBinding.instance.hasScheduledFrame);
}
Rect boundsFor(WidgetController controller, Finder item) {
@ -35,7 +35,7 @@ Future<void> main() async {
child: GalleryApp(testMode: true),
),
));
await SchedulerBinding.instance!.endOfFrame;
await SchedulerBinding.instance.endOfFrame;
await Future<void>.delayed(const Duration(milliseconds: 50));
debugPrint('==== MEMORY BENCHMARK ==== READY ====');
@ -49,9 +49,9 @@ Future<void> main() async {
child: GalleryApp(testMode: true),
),
));
await SchedulerBinding.instance!.endOfFrame;
await SchedulerBinding.instance.endOfFrame;
final WidgetController controller = LiveWidgetController(WidgetsBinding.instance!);
final WidgetController controller = LiveWidgetController(WidgetsBinding.instance);
debugPrint('Navigating...');
await controller.tap(find.text('Material'));

View File

@ -16,7 +16,7 @@ void main() {
// Disconnects semantics listener for testing purposes.
originalSemanticsListener = ui.window.onSemanticsEnabledChanged;
ui.window.onSemanticsEnabledChanged = null;
RendererBinding.instance?.setSemanticsEnabled(false);
RendererBinding.instance.setSemanticsEnabled(false);
// If the test passes, LifeCycleSpy will rewire the semantics listener back.
runApp(const LifeCycleSpy());
}
@ -46,15 +46,15 @@ class _LifeCycleSpyState extends State<LifeCycleSpy> with WidgetsBindingObserver
@override
void initState() {
super.initState();
WidgetsBinding.instance?.addObserver(this);
WidgetsBinding.instance.addObserver(this);
_actualLifeCycleSequence = <AppLifecycleState?>[
ServicesBinding.instance?.lifecycleState
ServicesBinding.instance.lifecycleState
];
}
@override
void dispose() {
WidgetsBinding.instance?.removeObserver(this);
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@ -70,7 +70,7 @@ class _LifeCycleSpyState extends State<LifeCycleSpy> with WidgetsBindingObserver
Widget build(BuildContext context) {
if (const ListEquality<AppLifecycleState?>().equals(_actualLifeCycleSequence, _expectedLifeCycleSequence)) {
// Rewires the semantics harness if test passes.
RendererBinding.instance?.setSemanticsEnabled(true);
RendererBinding.instance.setSemanticsEnabled(true);
ui.window.onSemanticsEnabledChanged = originalSemanticsListener;
}
return const MaterialApp(

View File

@ -960,7 +960,7 @@ class _PaintingState extends State<Painting> with SingleTickerProviderStateMixin
}
_text = buffer.toString();
});
SchedulerBinding.instance?.addPostFrameCallback((Duration duration) {
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
if (mounted && intrinsicKey.currentContext?.size?.height != controlKey.currentContext?.size?.height) {
debugPrint('Found some text that unexpectedly renders at different heights.');
debugPrint('Text: $_text');

View File

@ -32,18 +32,18 @@ void main() {
test('Image cache tracing', () async {
final TestImageStreamCompleter completer1 = TestImageStreamCompleter();
final TestImageStreamCompleter completer2 = TestImageStreamCompleter();
PaintingBinding.instance!.imageCache!.putIfAbsent(
PaintingBinding.instance.imageCache.putIfAbsent(
'Test',
() => completer1,
);
PaintingBinding.instance!.imageCache!.clear();
PaintingBinding.instance.imageCache.clear();
completer2.testSetImage(ImageInfo(image: await createTestImage()));
PaintingBinding.instance!.imageCache!.putIfAbsent(
PaintingBinding.instance.imageCache.putIfAbsent(
'Test2',
() => completer2,
);
PaintingBinding.instance!.imageCache!.evict('Test2');
PaintingBinding.instance.imageCache.evict('Test2');
final Timeline timeline = await vmService.getVMTimeline();
_expectTimelineEvents(

View File

@ -18,12 +18,12 @@ class _LifecycleWatcherState extends State<LifecycleWatcher>
@override
void initState() {
super.initState();
WidgetsBinding.instance!.addObserver(this);
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

View File

@ -13,6 +13,6 @@ void main() {
test('layers smoketest for rendering/custom_coordinate_systems.dart', () {
FlutterError.onError = (FlutterErrorDetails details) { throw details.exception; };
demo.main();
expect(SchedulerBinding.instance!.hasScheduledFrame, true);
expect(SchedulerBinding.instance.hasScheduledFrame, true);
});
}

View File

@ -13,6 +13,6 @@ void main() {
test('layers smoketest for rendering/flex_layout.dart', () {
FlutterError.onError = (FlutterErrorDetails details) { throw details.exception; };
demo.main();
expect(SchedulerBinding.instance!.hasScheduledFrame, true);
expect(SchedulerBinding.instance.hasScheduledFrame, true);
});
}

View File

@ -13,6 +13,6 @@ void main() {
test('layers smoketest for rendering/hello_world.dart', () {
FlutterError.onError = (FlutterErrorDetails details) { throw details.exception; };
demo.main();
expect(SchedulerBinding.instance!.hasScheduledFrame, true);
expect(SchedulerBinding.instance.hasScheduledFrame, true);
});
}

View File

@ -13,6 +13,6 @@ void main() {
test('layers smoketest for rendering/spinning_square.dart', () {
FlutterError.onError = (FlutterErrorDetails details) { throw details.exception; };
demo.main();
expect(SchedulerBinding.instance!.hasScheduledFrame, true);
expect(SchedulerBinding.instance.hasScheduledFrame, true);
});
}

View File

@ -13,6 +13,6 @@ void main() {
test('layers smoketest for rendering/touch_input.dart', () {
FlutterError.onError = (FlutterErrorDetails details) { throw details.exception; };
demo.main();
expect(SchedulerBinding.instance!.hasScheduledFrame, true);
expect(SchedulerBinding.instance.hasScheduledFrame, true);
});
}

View File

@ -73,7 +73,7 @@ void attachWidgetTreeToRenderTree(RenderProxyBox container) {
),
),
),
).attachToRenderTree(WidgetsBinding.instance!.buildOwner!, element);
).attachToRenderTree(WidgetsBinding.instance.buildOwner!, element);
}
Duration? timeBase;
@ -86,7 +86,7 @@ void rotate(Duration timeStamp) {
transformBox.setIdentity();
transformBox.rotateZ(delta);
WidgetsBinding.instance!.buildOwner!.buildScope(element!);
WidgetsBinding.instance.buildOwner!.buildScope(element!);
}
void main() {

View File

@ -567,7 +567,7 @@ class AnimationController extends Animation<double>
TickerFuture _animateToInternal(double target, { Duration? duration, Curve curve = Curves.linear }) {
double scale = 1.0;
if (SemanticsBinding.instance!.disableAnimations) {
if (SemanticsBinding.instance.disableAnimations) {
switch (animationBehavior) {
case AnimationBehavior.normal:
// Since the framework cannot handle zero duration animations, we run it at 5% of the normal
@ -688,7 +688,7 @@ class AnimationController extends Animation<double>
: upperBound + _kFlingTolerance.distance;
double scale = 1.0;
final AnimationBehavior behavior = animationBehavior ?? this.animationBehavior;
if (SemanticsBinding.instance!.disableAnimations) {
if (SemanticsBinding.instance.disableAnimations) {
switch (behavior) {
case AnimationBehavior.normal:
// TODO(jonahwilliams): determine a better process for setting velocity.

View File

@ -315,7 +315,7 @@ class _CupertinoContextMenuState extends State<CupertinoContextMenu> with Ticker
// because _ContextMenuRoute renders its first frame offscreen.
// Otherwise there would be a visible flash when nothing is rendered for
// one frame.
SchedulerBinding.instance!.addPostFrameCallback((Duration _) {
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
_lastOverlayEntry?.remove();
_lastOverlayEntry = null;
_openController.reset();
@ -742,7 +742,7 @@ class _ContextMenuRoute<T> extends PopupRoute<T> {
// Render one frame offstage in the final position so that we can take
// measurements of its layout and then animate to them.
SchedulerBinding.instance!.addPostFrameCallback((Duration _) {
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
_updateTweenRects();
_internalOffstage = false;
_setOffstageInternally();

View File

@ -585,7 +585,7 @@ class _CupertinoDatePickerDateTimeState extends State<CupertinoDatePicker> {
minuteController = FixedExtentScrollController(initialItem: initialDateTime.minute ~/ widget.minuteInterval);
dateController = FixedExtentScrollController(initialItem: 0);
PaintingBinding.instance!.systemFonts.addListener(_handleSystemFontsChange);
PaintingBinding.instance.systemFonts.addListener(_handleSystemFontsChange);
}
void _handleSystemFontsChange () {
@ -604,7 +604,7 @@ class _CupertinoDatePickerDateTimeState extends State<CupertinoDatePicker> {
minuteController.dispose();
meridiemController.dispose();
PaintingBinding.instance!.systemFonts.removeListener(_handleSystemFontsChange);
PaintingBinding.instance.systemFonts.removeListener(_handleSystemFontsChange);
super.dispose();
}
@ -930,7 +930,7 @@ class _CupertinoDatePickerDateTimeState extends State<CupertinoDatePicker> {
void _scrollToDate(DateTime newDate, DateTime fromDate) {
assert(newDate != null);
SchedulerBinding.instance!.addPostFrameCallback((Duration timestamp) {
SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
if (fromDate.year != newDate.year || fromDate.month != newDate.month || fromDate.day != newDate.day) {
_animateColumnControllerToItem(dateController, selectedDayFromInitial);
}
@ -1104,7 +1104,7 @@ class _CupertinoDatePickerDateState extends State<CupertinoDatePicker> {
monthController = FixedExtentScrollController(initialItem: selectedMonth - 1);
yearController = FixedExtentScrollController(initialItem: selectedYear);
PaintingBinding.instance!.systemFonts.addListener(_handleSystemFontsChange);
PaintingBinding.instance.systemFonts.addListener(_handleSystemFontsChange);
}
void _handleSystemFontsChange() {
@ -1120,7 +1120,7 @@ class _CupertinoDatePickerDateState extends State<CupertinoDatePicker> {
monthController.dispose();
yearController.dispose();
PaintingBinding.instance!.systemFonts.removeListener(_handleSystemFontsChange);
PaintingBinding.instance.systemFonts.removeListener(_handleSystemFontsChange);
super.dispose();
}
@ -1326,7 +1326,7 @@ class _CupertinoDatePickerDateState extends State<CupertinoDatePicker> {
void _scrollToDate(DateTime newDate) {
assert(newDate != null);
SchedulerBinding.instance!.addPostFrameCallback((Duration timestamp) {
SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
if (selectedYear != newDate.year) {
_animateColumnControllerToItem(yearController, newDate.year);
}
@ -1608,7 +1608,7 @@ class _CupertinoTimerPickerState extends State<CupertinoTimerPicker> {
if (widget.mode != CupertinoTimerPickerMode.hm)
selectedSecond = widget.initialTimerDuration.inSeconds % 60;
PaintingBinding.instance!.systemFonts.addListener(_handleSystemFontsChange);
PaintingBinding.instance.systemFonts.addListener(_handleSystemFontsChange);
}
void _handleSystemFontsChange() {
@ -1621,7 +1621,7 @@ class _CupertinoTimerPickerState extends State<CupertinoTimerPicker> {
@override
void dispose() {
PaintingBinding.instance!.systemFonts.removeListener(_handleSystemFontsChange);
PaintingBinding.instance.systemFonts.removeListener(_handleSystemFontsChange);
super.dispose();
}

View File

@ -506,10 +506,10 @@ class _CupertinoSliverRefreshControlState extends State<CupertinoSliverRefreshCo
nextState = RefreshIndicatorMode.done;
// Either schedule the RenderSliver to re-layout on the next frame
// when not currently in a frame or schedule it on the next frame.
if (SchedulerBinding.instance!.schedulerPhase == SchedulerPhase.idle) {
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle) {
setState(() => hasSliverLayoutExtent = false);
} else {
SchedulerBinding.instance!.addPostFrameCallback((Duration timestamp) {
SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
setState(() => hasSliverLayoutExtent = false);
});
}
@ -535,7 +535,7 @@ class _CupertinoSliverRefreshControlState extends State<CupertinoSliverRefreshCo
// Call onRefresh after this frame finished since the function is
// user supplied and we're always here in the middle of the sliver's
// performLayout.
SchedulerBinding.instance!.addPostFrameCallback((Duration timestamp) {
SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
refreshTask = widget.onRefresh!()..whenComplete(() {
if (mounted) {
setState(() => refreshTask = null);

View File

@ -7,6 +7,11 @@ Currently they do depend on dart:ui, but only for `VoidCallback` and
`hashValues` (and maybe one day `hashList` and `lerpDouble`), which
are all intended to be moved out of `dart:ui` and into `dart:core`.
There is currently also an unfortunate dependency on the platform
dispatcher logic (SingletonFlutterWindow, Brightness,
PlatformDispatcher, window), though that should probably move to the
'services' library.
See also:
* https://github.com/dart-lang/sdk/issues/27791 (`VoidCallback`)

View File

@ -14,10 +14,14 @@ import 'assertions.dart';
import 'basic_types.dart';
import 'constants.dart';
import 'debug.dart';
import 'diagnostics.dart';
import 'object.dart';
import 'platform.dart';
import 'print.dart';
// Examples can assume:
// mixin BarBinding on BindingBase { }
/// Signature for service extensions.
///
/// The returned map must not contain the keys "type" or "method", as
@ -27,21 +31,101 @@ import 'print.dart';
/// "method" key will be set to the full name of the method.
typedef ServiceExtensionCallback = Future<Map<String, dynamic>> Function(Map<String, String> parameters);
/// Base class for mixins that provide singleton services (also known as
/// "bindings").
/// Base class for mixins that provide singleton services.
///
/// To use this class in an `on` clause of a mixin, inherit from it and implement
/// [initInstances()]. The mixin is guaranteed to only be constructed once in
/// the lifetime of the app (more precisely, it will assert if constructed twice
/// in checked mode).
/// The Flutter engine ([dart:ui]) exposes some low-level services,
/// but these are typically not suitable for direct use, for example
/// because they only provide a single callback which an application
/// may wish to multiplex to allow multiple listeners.
///
/// The top-most layer used to write the application will have a concrete class
/// that inherits from [BindingBase] and uses all the various [BindingBase]
/// mixins (such as [ServicesBinding]). For example, the Widgets library in
/// Flutter introduces a binding called [WidgetsFlutterBinding]. The relevant
/// library defines how to create the binding. It could be implied (for example,
/// [WidgetsFlutterBinding] is automatically started from [runApp]), or the
/// application might be required to explicitly call the constructor.
/// Bindings provide the glue between these low-level APIs and the
/// higher-level framework APIs. They _bind_ the two together, whence
/// the name.
///
/// ## Implementing a binding mixin
///
/// A library would typically create a new binding mixin to expose a
/// feature in [dart:ui]. This is rare in general, but it is something
/// that an alternative framework would do, e.g. if a framework were
/// to replace the [widgets] library with an alternative API but still
/// wished to leverage the [services] and [foundation] libraries.
///
/// To create a binding mixin, declare a mixin `on` the [BindingBase] class
/// and whatever other bindings the concrete binding must implement for
/// this binding mixin to be useful.
///
/// The mixin is guaranteed to only be constructed once in the
/// lifetime of the app; this is handled by [initInstances].
///
/// A binding mixin must at a minimum implement the following features:
///
/// * The [initInstances] method, which must call `super.initInstances` and
/// set an `_instance` static field to `this`.
/// * An `instance` static getter, which must return that field using [checkInstance].
///
/// In addition, it should implement whatever singleton features the library needs.
///
/// As a general rule, the less can be placed in the binding, the
/// better. Prefer having APIs that takes objects rather than having
/// them refer to global singletons. Bindings are best limited to
/// exposing features that literally only exist once, for example, the
/// APIs in [dart:ui].
///
/// {@tool snippet}
///
/// Here is a basic example of a binding that implements these features. It relies on
/// another fictional binding called `BarBinding`.
///
/// ```dart
/// mixin FooBinding on BindingBase, BarBinding {
/// @override
/// void initInstances() {
/// super.initInstances();
/// _instance = this;
/// // ...binding initialization...
/// }
///
/// static FooBinding get instance => BindingBase.checkInstance(_instance);
/// static FooBinding? _instance;
///
/// // ...binding features...
/// }
/// ```
/// {@end-tool}
///
/// ## Implementing a binding class
///
/// The top-most layer used to write the application (e.g. the Flutter
/// [widgets] library) will have a concrete class that inherits from
/// [BindingBase] and uses all the various [BindingBase] mixins (such
/// as [ServicesBinding]). The [widgets] library in Flutter introduces
/// a binding called [WidgetsFlutterBinding].
///
/// A binding _class_ should mix in the relevant bindings from each
/// layer that it wishes to expose, and should have an
/// `ensureInitialized` method that constructs the class if that
/// layer's mixin's `_instance` field is null. This allows the binding
/// to be overriden by developers who have more specific needs, while
/// still allowing other code to call `ensureInitialized` when a binding
/// is needed.
///
/// {@tool snippet}
///
/// A typical binding class is shown below. The `ensureInitialized` method's
/// return type is the library's binding mixin, rather than the concrete
/// class.
///
/// ```dart
/// class FooLibraryBinding extends BindingBase with BarBinding, FooBinding {
/// static FooBinding ensureInitialized() {
/// if (FooBinding._instance == null) {
/// FooLibraryBinding();
/// }
/// return FooBinding.instance;
/// }
/// }
/// /// ```
/// {@end-tool}
abstract class BindingBase {
/// Default abstract constructor for bindings.
///
@ -51,6 +135,10 @@ abstract class BindingBase {
/// observatory service extensions, if any.
BindingBase() {
developer.Timeline.startSync('Framework initialization');
assert(() {
_debugConstructed = true;
return true;
}());
assert(!_debugInitialized);
initInstances();
@ -65,6 +153,7 @@ abstract class BindingBase {
developer.Timeline.finishSync();
}
bool _debugConstructed = false;
static bool _debugInitialized = false;
static bool _debugServiceExtensionsRegistered = false;
@ -131,10 +220,39 @@ abstract class BindingBase {
/// the platform and otherwise configure their services. Subclasses must call
/// "super.initInstances()".
///
/// By convention, if the service is to be provided as a singleton, it should
/// be exposed as `MixinClassName.instance`, a static getter that returns
/// The binding is not fully initialized when this method runs (for
/// example, other binding mixins may not yet have run their
/// [initInstances] method). For this reason, code in this method
/// should avoid invoking callbacks or synchronously triggering any
/// code that would normally assume that the bindings are ready.
///
/// {@tool snippet}
///
/// By convention, if the service is to be provided as a singleton,
/// it should be exposed as `MixinClassName.instance`, a static
/// getter with a non-nullable return type that returns
/// `MixinClassName._instance`, a static field that is set by
/// `initInstances()`.
/// `initInstances()`. To improve the developer experience, the
/// return value should actually be
/// `BindingBase.checkInstance(_instance)` (see [checkInstance]), as
/// in the example below.
///
/// ```dart
/// mixin BazBinding on BindingBase {
/// @override
/// void initInstances() {
/// super.initInstances();
/// _instance = this;
/// // ...binding initialization...
/// }
///
/// static BazBinding get instance => BindingBase.checkInstance(_instance);
/// static BazBinding? _instance;
///
/// // ...binding features...
/// }
/// ```
/// {@end-tool}
@protected
@mustCallSuper
void initInstances() {
@ -145,6 +263,100 @@ abstract class BindingBase {
}());
}
/// A method that shows a useful error message if the given binding
/// instance is not initialized.
///
/// See [initInstances] for advice on using this method.
///
/// This method either returns the argument or throws an exception.
/// In release mode it always returns the argument.
///
/// The type argument `T` should be the kind of binding mixin (e.g.
/// `SchedulerBinding`) that is calling the method. It is used in
/// error messages.
@protected
static T checkInstance<T extends BindingBase>(T? instance) {
assert(() {
if (!_debugInitialized && instance == null) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('Binding has not yet been initialized.'),
ErrorDescription('The "instance" getter on the $T binding mixin is only available once that binding has been initialized.'),
ErrorHint(
'Typically, this is done by calling "WidgetsFlutterBinding.ensureInitialized()" or "runApp()" (the '
'latter calls the former). Typically this call is done in the "void main()" method. The "ensureInitialized" method '
'is idempotent; calling it multiple times is not harmful. After calling that method, the "instance" getter will '
'return the binding.',
),
ErrorHint(
'In a test, one can call "TestWidgetsFlutterBinding.ensureInitialized()" as the first line in the test\'s "main()" method '
'to initialize the binding.',
),
ErrorHint(
'If $T is a custom binding mixin, there must also be a custom binding class, like WidgetsFlutterBinding, '
'but that mixes in the selected binding, and that is the class that must be constructed before using the "instance" getter.',
),
]);
}
if (instance == null) {
assert(_debugInitialized);
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('Binding mixin instance is null but bindings are already initialized.'),
ErrorDescription(
'The "instance" property of the $T binding mixin was accessed, but that binding was not initialized when '
'the "initInstances()" method was called.'
),
ErrorHint(
'This probably indicates that the $T mixin was not mixed into the class that was used to initialize the binding. '
'If this is a custom binding mixin, there must also be a custom binding class, like WidgetsFlutterBinding, '
'but that mixes in the selected binding. If this is a test binding, check that the binding being initialized '
'is the same as the one into which the test binding is mixed.'
),
]);
}
try {
assert(instance != null);
if (instance._debugConstructed && !_debugInitialized) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('Binding initialized without calling initInstances.'),
ErrorDescription('An instance of $T is non-null, but BindingBase.initInstances() has not yet been called.'),
ErrorHint(
'This could happen because a binding mixin was somehow used outside of the normal binding mechanisms, or because '
'the binding\'s initInstances() method did not call "super.initInstances()".'
),
ErrorHint(
'This could also happen if some code was invoked that used the binding while the binding was initializing, '
'for example if the "initInstances" method invokes a callback. Bindings should not invoke callbacks before '
'"initInstances" has completed.'
),
]);
}
if (!instance._debugConstructed) {
// The state of _debugInitialized doesn't matter in this failure mode.
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('Binding did not complete initialization.'),
ErrorDescription('An instance of $T is non-null, but the BindingBase() constructor has not yet been called.'),
ErrorHint(
'This could also happen if some code was invoked that used the binding while the binding was initializing, '
"for example if the binding's constructor itself invokes a callback. Bindings should not invoke callbacks "
'before "initInstances" has completed.'
),
]);
}
} on NoSuchMethodError {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('Binding does not extend BindingBase'),
ErrorDescription('An instance of $T was created but the BindingBase constructor was not called.'),
ErrorHint(
'This could happen because the binding was implemented using "implements" rather than "extends" or "with". '
'Concrete binding classes must extend or mix in BindingBase.'
),
]);
}
return true;
}());
return instance!;
}
/// Called when the binding is initialized, to register service
/// extensions.
///
@ -555,7 +767,7 @@ abstract class BindingBase {
/// available in debug and profile mode.
///
/// ```dart
/// void myRegistrationFunction() {
/// void myOtherRegistrationFunction() {
/// // kReleaseMode is defined in the 'flutter/foundation.dart' package.
/// if (!kReleaseMode) {
/// // Register your service extension here.

View File

@ -73,7 +73,7 @@ class _Resampler {
// Add `event` for resampling or dispatch it directly if
// not a touch event.
void addOrDispatch(PointerEvent event) {
final SchedulerBinding? scheduler = SchedulerBinding.instance;
final SchedulerBinding scheduler = SchedulerBinding.instance;
assert(scheduler != null);
// Add touch event to resampler or dispatch pointer event directly.
if (event.kind == PointerDeviceKind.touch) {
@ -94,9 +94,10 @@ class _Resampler {
//
// The `samplingOffset` is relative to the current frame time, which
// can be in the past when we're not actively resampling.
//
// The `samplingClock` is the clock used to determine frame time age.
void sample(Duration samplingOffset, SamplingClock clock) {
final SchedulerBinding? scheduler = SchedulerBinding.instance;
final SchedulerBinding scheduler = SchedulerBinding.instance;
assert(scheduler != null);
// Initialize `_frameTime` if needed. This will be used for periodic
@ -156,7 +157,7 @@ class _Resampler {
// Add a post frame callback as this avoids producing unnecessary
// frames but ensures that sampling phase is adjusted to frame
// time when frames are produced.
scheduler?.addPostFrameCallback((_) {
scheduler.addPostFrameCallback((_) {
_frameCallbackScheduled = false;
// We use `currentSystemFrameTimeStamp` here as it's critical that
// sample time is in the same clock as the event time stamps, and
@ -259,16 +260,20 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
window.onPointerDataPacket = _handlePointerDataPacket;
}
/// The singleton instance of this object.
///
/// Provides access to the features exposed by this mixin. The binding must
/// be initialized before using this getter; this is typically done by calling
/// [runApp] or [WidgetsFlutterBinding.ensureInitialized].
static GestureBinding get instance => BindingBase.checkInstance(_instance);
static GestureBinding? _instance;
@override
void unlocked() {
super.unlocked();
_flushPointerEventQueue();
}
/// The singleton instance of this object.
static GestureBinding? get instance => _instance;
static GestureBinding? _instance;
final Queue<PointerEvent> _pendingPointerEvents = Queue<PointerEvent>();
void _handlePointerDataPacket(ui.PointerDataPacket packet) {

View File

@ -231,8 +231,8 @@ abstract class MultiDragGestureRecognizer extends GestureRecognizer {
assert(!_pointers!.containsKey(event.pointer));
final MultiDragPointerState state = createNewPointerState(event);
_pointers![event.pointer] = state;
GestureBinding.instance!.pointerRouter.addRoute(event.pointer, _handleEvent);
state._setArenaEntry(GestureBinding.instance!.gestureArena.add(event.pointer, this));
GestureBinding.instance.pointerRouter.addRoute(event.pointer, _handleEvent);
state._setArenaEntry(GestureBinding.instance.gestureArena.add(event.pointer, this));
}
/// Subclasses should override this method to create per-pointer state
@ -312,7 +312,7 @@ abstract class MultiDragGestureRecognizer extends GestureRecognizer {
return;
}
assert(_pointers!.containsKey(pointer));
GestureBinding.instance!.pointerRouter.removeRoute(pointer, _handleEvent);
GestureBinding.instance.pointerRouter.removeRoute(pointer, _handleEvent);
_pointers!.remove(pointer)!.dispose();
}

View File

@ -79,14 +79,14 @@ class _TapTracker {
void startTrackingPointer(PointerRoute route, Matrix4? transform) {
if (!_isTrackingPointer) {
_isTrackingPointer = true;
GestureBinding.instance!.pointerRouter.addRoute(pointer, route, transform);
GestureBinding.instance.pointerRouter.addRoute(pointer, route, transform);
}
}
void stopTrackingPointer(PointerRoute route) {
if (_isTrackingPointer) {
_isTrackingPointer = false;
GestureBinding.instance!.pointerRouter.removeRoute(pointer, route);
GestureBinding.instance.pointerRouter.removeRoute(pointer, route);
}
}
@ -242,7 +242,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
_stopDoubleTapTimer();
final _TapTracker tracker = _TapTracker(
event: event,
entry: GestureBinding.instance!.gestureArena.add(event.pointer, this),
entry: GestureBinding.instance.gestureArena.add(event.pointer, this),
doubleTapMinTime: kDoubleTapMinTime,
);
_trackers[event.pointer] = tracker;
@ -311,14 +311,14 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
final _TapTracker tracker = _firstTap!;
_firstTap = null;
_reject(tracker);
GestureBinding.instance!.gestureArena.release(tracker.pointer);
GestureBinding.instance.gestureArena.release(tracker.pointer);
}
_clearTrackers();
}
void _registerFirstTap(_TapTracker tracker) {
_startDoubleTapTimer();
GestureBinding.instance!.gestureArena.hold(tracker.pointer);
GestureBinding.instance.gestureArena.hold(tracker.pointer);
// Note, order is important below in order for the clear -> reject logic to
// work properly.
_freezeTracker(tracker);
@ -383,7 +383,7 @@ class _TapGesture extends _TapTracker {
}) : _lastPosition = OffsetPair.fromEventPosition(event),
super(
event: event as PointerDownEvent,
entry: GestureBinding.instance!.gestureArena.add(event.pointer, gestureRecognizer),
entry: GestureBinding.instance.gestureArena.add(event.pointer, gestureRecognizer),
doubleTapMinTime: kDoubleTapMinTime,
) {
startTrackingPointer(handleEvent, event.transform);

View File

@ -30,7 +30,7 @@ bool _isSameEvent(PointerSignalEvent event1, PointerSignalEvent event2) {
///
/// ```dart
/// void handleSignalEvent(PointerSignalEvent event) {
/// GestureBinding.instance!.pointerSignalResolver.register(event, (PointerSignalEvent event) {
/// GestureBinding.instance.pointerSignalResolver.register(event, (PointerSignalEvent event) {
/// // handle the event...
/// });
/// }
@ -96,7 +96,7 @@ bool _isSameEvent(PointerSignalEvent event1, PointerSignalEvent event2) {
/// child: Listener(
/// onPointerSignal: (PointerSignalEvent event) {
/// if (widget.useResolver) {
/// GestureBinding.instance!.pointerSignalResolver.register(event, (PointerSignalEvent event) {
/// GestureBinding.instance.pointerSignalResolver.register(event, (PointerSignalEvent event) {
/// rotateColor();
/// });
/// } else {

View File

@ -317,7 +317,7 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
void dispose() {
resolve(GestureDisposition.rejected);
for (final int pointer in _trackedPointers)
GestureBinding.instance!.pointerRouter.removeRoute(pointer, handleEvent);
GestureBinding.instance.pointerRouter.removeRoute(pointer, handleEvent);
_trackedPointers.clear();
assert(_entries.isEmpty);
super.dispose();
@ -347,7 +347,7 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
GestureArenaEntry _addPointerToArena(int pointer) {
if (_team != null)
return _team!.add(pointer, this);
return GestureBinding.instance!.gestureArena.add(pointer, this);
return GestureBinding.instance.gestureArena.add(pointer, this);
}
/// Causes events related to the given pointer ID to be routed to this recognizer.
@ -366,7 +366,7 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
/// This is called by [OneSequenceGestureRecognizer.addAllowedPointer].
@protected
void startTrackingPointer(int pointer, [Matrix4? transform]) {
GestureBinding.instance!.pointerRouter.addRoute(pointer, handleEvent, transform);
GestureBinding.instance.pointerRouter.addRoute(pointer, handleEvent, transform);
_trackedPointers.add(pointer);
assert(!_entries.containsValue(pointer));
_entries[pointer] = _addPointerToArena(pointer);
@ -381,7 +381,7 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
@protected
void stopTrackingPointer(int pointer) {
if (_trackedPointers.contains(pointer)) {
GestureBinding.instance!.pointerRouter.removeRoute(pointer, handleEvent);
GestureBinding.instance.pointerRouter.removeRoute(pointer, handleEvent);
_trackedPointers.remove(pointer);
if (_trackedPointers.isEmpty)
didStopTrackingLastPointer(pointer);

View File

@ -61,7 +61,7 @@ class _CombiningGestureArenaMember extends GestureArenaMember {
assert(!_resolved);
assert(_pointer == pointer);
_members.add(member);
_entry ??= GestureBinding.instance!.gestureArena.add(pointer, this);
_entry ??= GestureBinding.instance.gestureArena.add(pointer, this);
return _CombiningGestureArenaEntry(this, member);
}

View File

@ -844,7 +844,7 @@ class _PackageLicensePageState extends State<_PackageLicensePage> {
return true;
}());
final List<LicenseParagraph> paragraphs =
await SchedulerBinding.instance!.scheduleTask<List<LicenseParagraph>>(
await SchedulerBinding.instance.scheduleTask<List<LicenseParagraph>>(
license.paragraphs.toList,
Priority.animation,
debugLabel: 'License',
@ -1507,15 +1507,13 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
@override
void openDetailPage(Object arguments) {
SchedulerBinding.instance!
.addPostFrameCallback((_) => _detailArguments.value = arguments);
SchedulerBinding.instance.addPostFrameCallback((_) => _detailArguments.value = arguments);
_MasterDetailFlow.of(context)!.openDetailPage(arguments);
}
@override
void setInitialDetailPage(Object arguments) {
SchedulerBinding.instance!
.addPostFrameCallback((_) => _detailArguments.value = arguments);
SchedulerBinding.instance.addPostFrameCallback((_) => _detailArguments.value = arguments);
_MasterDetailFlow.of(context)!.setInitialDetailPage(arguments);
}

View File

@ -301,7 +301,7 @@ class _AutocompleteOptions<T extends Object> extends StatelessWidget {
builder: (BuildContext context) {
final bool highlight = AutocompleteHighlightedOption.of(context) == index;
if (highlight) {
SchedulerBinding.instance!.addPostFrameCallback((Duration timeStamp) {
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
Scrollable.ensureVisible(context, alignment: 0.5);
});
}

View File

@ -533,7 +533,7 @@ class _MonthPickerState extends State<_MonthPicker> {
super.didUpdateWidget(oldWidget);
if (widget.initialMonth != oldWidget.initialMonth && widget.initialMonth != _currentMonth) {
// We can't interrupt this widget build with a scroll, so do it next frame
WidgetsBinding.instance!.addPostFrameCallback(
WidgetsBinding.instance.addPostFrameCallback(
(Duration timeStamp) => _showMonth(widget.initialMonth, jump: true),
);
}

View File

@ -1237,16 +1237,16 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
),
};
focusNode!.addListener(_handleFocusChanged);
final FocusManager focusManager = WidgetsBinding.instance!.focusManager;
final FocusManager focusManager = WidgetsBinding.instance.focusManager;
_focusHighlightMode = focusManager.highlightMode;
focusManager.addHighlightModeListener(_handleFocusHighlightModeChange);
}
@override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
WidgetsBinding.instance.removeObserver(this);
_removeDropdownRoute();
WidgetsBinding.instance!.focusManager.removeHighlightModeListener(_handleFocusHighlightModeChange);
WidgetsBinding.instance.focusManager.removeHighlightModeListener(_handleFocusHighlightModeChange);
focusNode!.removeListener(_handleFocusChanged);
_internalNode?.dispose();
super.dispose();

View File

@ -161,7 +161,7 @@ class _InputDatePickerFormFieldState extends State<InputDatePickerFormField> {
super.didUpdateWidget(oldWidget);
if (widget.initialDate != oldWidget.initialDate) {
// Can't update the form field in the middle of a build, so do it next frame
WidgetsBinding.instance!.addPostFrameCallback((Duration timeStamp) {
WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) {
setState(() {
_selectedDate = widget.initialDate;
_updateValueForSelectedDate();

View File

@ -833,7 +833,7 @@ class _DialPainter extends CustomPainter {
required this.theta,
required this.textDirection,
required this.selectedValue,
}) : super(repaint: PaintingBinding.instance!.systemFonts);
}) : super(repaint: PaintingBinding.instance.systemFonts);
final List<_TappableLabel> primaryLabels;
final List<_TappableLabel> secondaryLabels;

View File

@ -269,7 +269,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
@override
void initState() {
super.initState();
_mouseIsConnected = RendererBinding.instance!.mouseTracker.mouseIsConnected;
_mouseIsConnected = RendererBinding.instance.mouseTracker.mouseIsConnected;
_controller = AnimationController(
duration: _fadeInDuration,
reverseDuration: _fadeOutDuration,
@ -277,10 +277,10 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
)
..addStatusListener(_handleStatusChanged);
// Listen to see when a mouse is added.
RendererBinding.instance!.mouseTracker.addListener(_handleMouseTrackerChange);
RendererBinding.instance.mouseTracker.addListener(_handleMouseTrackerChange);
// Listen to global pointer events so that we can hide a tooltip immediately
// if some other control is clicked on.
GestureBinding.instance!.pointerRouter.addGlobalRoute(_handlePointerEvent);
GestureBinding.instance.pointerRouter.addGlobalRoute(_handlePointerEvent);
}
// https://material.io/components/tooltips#specs
@ -325,7 +325,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
if (!mounted) {
return;
}
final bool mouseIsConnected = RendererBinding.instance!.mouseTracker.mouseIsConnected;
final bool mouseIsConnected = RendererBinding.instance.mouseTracker.mouseIsConnected;
if (mouseIsConnected != _mouseIsConnected) {
setState(() {
_mouseIsConnected = mouseIsConnected;
@ -456,8 +456,8 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
@override
void dispose() {
GestureBinding.instance!.pointerRouter.removeGlobalRoute(_handlePointerEvent);
RendererBinding.instance!.mouseTracker.removeListener(_handleMouseTrackerChange);
GestureBinding.instance.pointerRouter.removeGlobalRoute(_handlePointerEvent);
RendererBinding.instance.mouseTracker.removeListener(_handleMouseTrackerChange);
_removeEntry();
_controller.dispose();
super.dispose();

View File

@ -118,7 +118,7 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm
// have had a chance to track the key in the cache at all.
// Schedule a microtask to give the cache a chance to add the key.
scheduleMicrotask(() {
PaintingBinding.instance!.imageCache!.evict(key);
PaintingBinding.instance.imageCache.evict(key);
});
rethrow;
} finally {

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:typed_data' show Uint8List;
import 'dart:ui' as ui show instantiateImageCodec, Codec;
import 'package:flutter/foundation.dart';
@ -26,7 +25,11 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
}
/// The current [PaintingBinding], if one has been created.
static PaintingBinding? get instance => _instance;
///
/// Provides access to the features exposed by this mixin. The binding must
/// be initialized before using this getter; this is typically done by calling
/// [runApp] or [WidgetsFlutterBinding.ensureInitialized].
static PaintingBinding get instance => BindingBase.checkInstance(_instance);
static PaintingBinding? _instance;
/// [ShaderWarmUp] instance to be executed during [initInstances].
@ -67,8 +70,8 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
///
/// The image cache is created during startup by the [createImageCache]
/// method.
ImageCache? get imageCache => _imageCache;
ImageCache? _imageCache;
ImageCache get imageCache => _imageCache;
late ImageCache _imageCache;
/// Creates the [ImageCache] singleton (accessible via [imageCache]).
///
@ -114,14 +117,14 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
@override
void evict(String asset) {
super.evict(asset);
imageCache!.clear();
imageCache!.clearLiveImages();
imageCache.clear();
imageCache.clearLiveImages();
}
@override
void handleMemoryPressure() {
super.handleMemoryPressure();
imageCache?.clear();
imageCache.clear();
}
/// Listenable that notifies when the available fonts on the system have
@ -176,4 +179,4 @@ class _SystemFontsNotifier extends Listenable {
///
/// The image cache is created during startup by the [PaintingBinding]'s
/// [PaintingBinding.createImageCache] method.
ImageCache? get imageCache => PaintingBinding.instance!.imageCache;
ImageCache get imageCache => PaintingBinding.instance.imageCache;

View File

@ -539,7 +539,7 @@ void paintImage({
_pendingImageSizeInfo[sizeInfo.source!] = sizeInfo;
}
debugOnPaintImage?.call(sizeInfo);
SchedulerBinding.instance!.addPostFrameCallback((Duration timeStamp) {
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
_lastFrameImageSizeInfo = _pendingImageSizeInfo.values.toSet();
if (_pendingImageSizeInfo.isEmpty) {
return;

View File

@ -622,7 +622,7 @@ abstract class _CachedImageBase {
assert(handle != null);
// Give any interested parties a chance to listen to the stream before we
// potentially dispose it.
SchedulerBinding.instance!.addPostFrameCallback((Duration timeStamp) {
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
assert(handle != null);
handle?.dispose();
handle = null;

View File

@ -21,7 +21,7 @@ import 'binding.dart';
/// [PaintingBinding.instantiateImageCodec], and therefore can be mocked in
/// tests.
Future<ui.Image> decodeImageFromList(Uint8List bytes) async {
final ui.Codec codec = await PaintingBinding.instance!.instantiateImageCodec(bytes);
final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodec(bytes);
final ui.FrameInfo frameInfo = await codec.getNextFrame();
return frameInfo.image;
}

View File

@ -387,7 +387,7 @@ abstract class ImageProvider<T extends Object> {
_createErrorHandlerAndKey(
configuration,
(T key, ImageErrorListener innerHandleError) {
completer.complete(PaintingBinding.instance!.imageCache!.statusForKey(key));
completer.complete(PaintingBinding.instance.imageCache.statusForKey(key));
},
(T? key, Object exception, StackTrace? stack) async {
if (handleError != null) {
@ -492,7 +492,7 @@ abstract class ImageProvider<T extends Object> {
// the image we want before getting to this method. We should avoid calling
// load again, but still update the image cache with LRU information.
if (stream.completer != null) {
final ImageStreamCompleter? completer = PaintingBinding.instance!.imageCache!.putIfAbsent(
final ImageStreamCompleter? completer = PaintingBinding.instance.imageCache.putIfAbsent(
key,
() => stream.completer!,
onError: handleError,
@ -500,9 +500,9 @@ abstract class ImageProvider<T extends Object> {
assert(identical(completer, stream.completer));
return;
}
final ImageStreamCompleter? completer = PaintingBinding.instance!.imageCache!.putIfAbsent(
final ImageStreamCompleter? completer = PaintingBinding.instance.imageCache.putIfAbsent(
key,
() => load(key, PaintingBinding.instance!.instantiateImageCodec),
() => load(key, PaintingBinding.instance.instantiateImageCodec),
onError: handleError,
);
if (completer != null) {
@ -557,7 +557,7 @@ abstract class ImageProvider<T extends Object> {
Future<bool> evict({ ImageCache? cache, ImageConfiguration configuration = ImageConfiguration.empty }) async {
cache ??= imageCache;
final T key = await obtainKey(configuration);
return cache!.evict(key);
return cache.evict(key);
}
/// Converts an ImageProvider's settings plus an ImageConfiguration to a key
@ -674,11 +674,11 @@ abstract class AssetBundleImageProvider extends ImageProvider<AssetBundleImageKe
try {
data = await key.bundle.load(key.name);
} on FlutterError {
PaintingBinding.instance!.imageCache!.evict(key);
PaintingBinding.instance.imageCache.evict(key);
rethrow;
}
if (data == null) {
PaintingBinding.instance!.imageCache!.evict(key);
PaintingBinding.instance.imageCache.evict(key);
throw StateError('Unable to read data');
}
return decode(data.buffer.asUint8List());
@ -891,7 +891,7 @@ class FileImage extends ImageProvider<FileImage> {
if (bytes.lengthInBytes == 0) {
// The file may become available later.
PaintingBinding.instance!.imageCache!.evict(key);
PaintingBinding.instance.imageCache.evict(key);
throw StateError('$file is empty and cannot be loaded as an image.');
}

View File

@ -964,7 +964,7 @@ class MultiFrameImageStreamCompleter extends ImageStreamCompleter {
return;
}
_frameCallbackScheduled = true;
SchedulerBinding.instance!.scheduleFrameCallback(_handleAppFrame);
SchedulerBinding.instance.scheduleFrameCallback(_handleAppFrame);
}
void _emitFrame(ImageInfo imageInfo) {

View File

@ -49,7 +49,11 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
}
/// The current [RendererBinding], if one has been created.
static RendererBinding? get instance => _instance;
///
/// Provides access to the features exposed by this mixin. The binding must
/// be initialized before using this getter; this is typically done by calling
/// [runApp] or [WidgetsFlutterBinding.ensureInitialized].
static RendererBinding get instance => BindingBase.checkInstance(_instance);
static RendererBinding? _instance;
@override
@ -114,7 +118,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
registerServiceExtension(
name: 'debugDumpLayerTree',
callback: (Map<String, String> parameters) async {
final String data = RendererBinding.instance?.renderView.debugLayer?.toStringDeep() ?? 'Layer tree unavailable.';
final String data = RendererBinding.instance.renderView.debugLayer?.toStringDeep() ?? 'Layer tree unavailable.';
return <String, Object>{
'data': data,
};
@ -128,7 +132,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
registerServiceExtension(
name: 'debugDumpRenderTree',
callback: (Map<String, String> parameters) async {
final String data = RendererBinding.instance?.renderView.toStringDeep() ?? 'Render tree unavailable.';
final String data = RendererBinding.instance.renderView.toStringDeep();
return <String, Object>{
'data': data,
};
@ -138,7 +142,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
registerServiceExtension(
name: 'debugDumpSemanticsTreeInTraversalOrder',
callback: (Map<String, String> parameters) async {
final String data = RendererBinding.instance?.renderView.debugSemantics
final String data = RendererBinding.instance.renderView.debugSemantics
?.toStringDeep(childOrder: DebugSemanticsDumpOrder.traversalOrder) ?? 'Semantics not collected.';
return <String, Object>{
'data': data,
@ -149,7 +153,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
registerServiceExtension(
name: 'debugDumpSemanticsTreeInInverseHitTestOrder',
callback: (Map<String, String> parameters) async {
final String data = RendererBinding.instance?.renderView.debugSemantics
final String data = RendererBinding.instance.renderView.debugSemantics
?.toStringDeep(childOrder: DebugSemanticsDumpOrder.inverseHitTest) ?? 'Semantics not collected.';
return <String, Object>{
'data': data,
@ -229,7 +233,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
/// Querying [PlatformDispatcher.platformBrightness].
///
/// ```dart
/// final Brightness brightness = WidgetsBinding.instance!.platformDispatcher.platformBrightness;
/// final Brightness brightness = WidgetsBinding.instance.platformDispatcher.platformBrightness;
/// ```
/// {@end-tool}
///
@ -338,7 +342,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
_debugMouseTrackerUpdateScheduled = true;
return true;
}());
SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
assert(_debugMouseTrackerUpdateScheduled);
assert(() {
_debugMouseTrackerUpdateScheduled = false;
@ -501,19 +505,19 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
child.markNeedsPaint();
child.visitChildren(visitor);
};
instance?.renderView.visitChildren(visitor);
instance.renderView.visitChildren(visitor);
return endOfFrame;
}
}
/// Prints a textual representation of the entire render tree.
void debugDumpRenderTree() {
debugPrint(RendererBinding.instance?.renderView.toStringDeep() ?? 'Render tree unavailable.');
debugPrint(RendererBinding.instance.renderView.toStringDeep());
}
/// Prints a textual representation of the entire layer tree.
void debugDumpLayerTree() {
debugPrint(RendererBinding.instance?.renderView.debugLayer?.toStringDeep() ?? 'Layer tree unavailable.');
debugPrint(RendererBinding.instance.renderView.debugLayer?.toStringDeep());
}
/// Prints a textual representation of the entire semantics tree.
@ -523,16 +527,27 @@ void debugDumpLayerTree() {
/// The order in which the children of a [SemanticsNode] will be printed is
/// controlled by the [childOrder] parameter.
void debugDumpSemanticsTree(DebugSemanticsDumpOrder childOrder) {
debugPrint(RendererBinding.instance?.renderView.debugSemantics?.toStringDeep(childOrder: childOrder) ?? 'Semantics not collected.');
debugPrint(RendererBinding.instance.renderView.debugSemantics?.toStringDeep(childOrder: childOrder) ?? 'Semantics not collected.');
}
/// A concrete binding for applications that use the Rendering framework
/// directly. This is the glue that binds the framework to the Flutter engine.
///
/// When using the rendering framework directly, this binding, or one that
/// implements the same interfaces, must be used. The following
/// mixins are used to implement this binding:
///
/// * [GestureBinding], which implements the basics of hit testing.
/// * [SchedulerBinding], which introduces the concepts of frames.
/// * [ServicesBinding], which provides access to the plugin subsystem.
/// * [SemanticsBinding], which supports accessibility.
/// * [PaintingBinding], which enables decoding images.
/// * [RendererBinding], which handles the render tree.
///
/// You would only use this binding if you are writing to the
/// rendering layer directly. If you are writing to a higher-level
/// library, such as the Flutter Widgets library, then you would use
/// that layer's binding.
/// that layer's binding (see [WidgetsFlutterBinding]).
class RenderingFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, SemanticsBinding, PaintingBinding, RendererBinding {
/// Creates a binding for the rendering layer.
///
@ -545,4 +560,18 @@ class RenderingFlutterBinding extends BindingBase with GestureBinding, Scheduler
assert(renderView != null);
renderView.child = root;
}
/// Returns an instance of the binding that implements
/// [RendererBinding]. If no binding has yet been initialized, the
/// [RenderingFlutterBinding] class is used to create and initialize
/// one.
///
/// You need to call this method before using the rendering framework
/// if you are using it directly. If you are using the widgets framework,
/// see [WidgetsFlutterBinding.ensureInitialized].
static RendererBinding ensureInitialized() {
if (RendererBinding._instance == null)
RenderingFlutterBinding();
return RendererBinding.instance;
}
}

View File

@ -3498,12 +3498,12 @@ mixin RelayoutWhenSystemFontsChangeMixin on RenderObject {
@override
void attach(covariant PipelineOwner owner) {
super.attach(owner);
PaintingBinding.instance!.systemFonts.addListener(systemFontsDidChange);
PaintingBinding.instance.systemFonts.addListener(systemFontsDidChange);
}
@override
void detach() {
PaintingBinding.instance!.systemFonts.removeListener(systemFontsDidChange);
PaintingBinding.instance.systemFonts.removeListener(systemFontsDidChange);
super.detach();
}
}

View File

@ -408,12 +408,12 @@ class RenderUiKitView extends RenderBox {
@override
void attach(PipelineOwner owner) {
super.attach(owner);
GestureBinding.instance!.pointerRouter.addGlobalRoute(_handleGlobalPointerEvent);
GestureBinding.instance.pointerRouter.addGlobalRoute(_handleGlobalPointerEvent);
}
@override
void detach() {
GestureBinding.instance!.pointerRouter.removeGlobalRoute(_handleGlobalPointerEvent);
GestureBinding.instance.pointerRouter.removeGlobalRoute(_handleGlobalPointerEvent);
_gestureRecognizer!.reset();
super.detach();
}

View File

@ -18,16 +18,18 @@ export 'dart:ui' show AppLifecycleState, VoidCallback, FrameTiming;
/// Slows down animations by this factor to help in development.
double get timeDilation => _timeDilation;
double _timeDilation = 1.0;
/// Setting the time dilation automatically calls [SchedulerBinding.resetEpoch]
/// to ensure that time stamps seen by consumers of the scheduler binding are
/// always increasing.
/// If the [SchedulerBinding] has been initialized, setting the time dilation
/// automatically calls [SchedulerBinding.resetEpoch] to ensure that time stamps
/// seen by consumers of the scheduler binding are always increasing.
///
/// It is safe to set this before initializing the binding.
set timeDilation(double value) {
assert(value > 0.0);
if (_timeDilation == value)
return;
// We need to resetEpoch first so that we capture start of the epoch with the
// current time dilation.
SchedulerBinding.instance?.resetEpoch();
// If the binding has been created, we need to resetEpoch first so that we
// capture start of the epoch with the current time dilation.
SchedulerBinding._instance?.resetEpoch();
_timeDilation = value;
}
@ -208,6 +210,14 @@ mixin SchedulerBinding on BindingBase {
}
}
/// The current [SchedulerBinding], if one has been created.
///
/// Provides access to the features exposed by this mixin. The binding must
/// be initialized before using this getter; this is typically done by calling
/// [runApp] or [WidgetsFlutterBinding.ensureInitialized].
static SchedulerBinding get instance => BindingBase.checkInstance(_instance);
static SchedulerBinding? _instance;
final List<TimingsCallback> _timingsCallbacks = <TimingsCallback>[];
/// Add a [TimingsCallback] that receives [FrameTiming] sent from
@ -307,10 +317,6 @@ mixin SchedulerBinding on BindingBase {
}
}
/// The current [SchedulerBinding], if one has been created.
static SchedulerBinding? get instance => _instance;
static SchedulerBinding? _instance;
@override
void initServiceExtensions() {
super.initServiceExtensions();

View File

@ -113,9 +113,9 @@ class Ticker {
return false;
if (muted)
return false;
if (SchedulerBinding.instance!.framesEnabled)
if (SchedulerBinding.instance.framesEnabled)
return true;
if (SchedulerBinding.instance!.schedulerPhase != SchedulerPhase.idle)
if (SchedulerBinding.instance.schedulerPhase != SchedulerPhase.idle)
return true; // for example, we might be in a warm-up frame or forced frame
return false;
}
@ -161,9 +161,9 @@ class Ticker {
if (shouldScheduleTick) {
scheduleTick();
}
if (SchedulerBinding.instance!.schedulerPhase.index > SchedulerPhase.idle.index &&
SchedulerBinding.instance!.schedulerPhase.index < SchedulerPhase.postFrameCallbacks.index)
_startTime = SchedulerBinding.instance!.currentFrameTimeStamp;
if (SchedulerBinding.instance.schedulerPhase.index > SchedulerPhase.idle.index &&
SchedulerBinding.instance.schedulerPhase.index < SchedulerPhase.postFrameCallbacks.index)
_startTime = SchedulerBinding.instance.currentFrameTimeStamp;
return _future!;
}
@ -250,7 +250,7 @@ class Ticker {
void scheduleTick({ bool rescheduling = false }) {
assert(!scheduled);
assert(shouldScheduleTick);
_animationId = SchedulerBinding.instance!.scheduleFrameCallback(_tick, rescheduling: rescheduling);
_animationId = SchedulerBinding.instance.scheduleFrameCallback(_tick, rescheduling: rescheduling);
}
/// Cancels the frame callback that was requested by [scheduleTick], if any.
@ -262,7 +262,7 @@ class Ticker {
@protected
void unscheduleTick() {
if (scheduled) {
SchedulerBinding.instance!.cancelFrameCallbackWithId(_animationId!);
SchedulerBinding.instance.cancelFrameCallbackWithId(_animationId!);
_animationId = null;
}
assert(!shouldScheduleTick);

View File

@ -13,10 +13,6 @@ export 'dart:ui' show AccessibilityFeatures;
/// The glue between the semantics layer and the Flutter engine.
// TODO(jonahwilliams): move the remaining semantic related bindings here.
mixin SemanticsBinding on BindingBase {
/// The current [SemanticsBinding], if one has been created.
static SemanticsBinding? get instance => _instance;
static SemanticsBinding? _instance;
@override
void initInstances() {
super.initInstances();
@ -24,6 +20,14 @@ mixin SemanticsBinding on BindingBase {
_accessibilityFeatures = window.accessibilityFeatures;
}
/// The current [SemanticsBinding], if one has been created.
///
/// Provides access to the features exposed by this mixin. The binding must
/// be initialized before using this getter; this is typically done by calling
/// [runApp] or [WidgetsFlutterBinding.ensureInitialized].
static SemanticsBinding get instance => BindingBase.checkInstance(_instance);
static SemanticsBinding? _instance;
/// Called when the platform accessibility features change.
///
/// See [dart:ui.PlatformDispatcher.onAccessibilityFeaturesChanged].

View File

@ -2938,7 +2938,7 @@ class SemanticsOwner extends ChangeNotifier {
}
}
visitedNodes.sort((SemanticsNode a, SemanticsNode b) => a.depth - b.depth);
final ui.SemanticsUpdateBuilder builder = SemanticsBinding.instance!.createSemanticsUpdateBuilder();
final ui.SemanticsUpdateBuilder builder = SemanticsBinding.instance.createSemanticsUpdateBuilder();
for (final SemanticsNode node in visitedNodes) {
assert(node.parent?._dirty != true); // could be null (no parent) or false (not dirty)
// The _serialize() method marks the node as not dirty, and
@ -2959,7 +2959,7 @@ class SemanticsOwner extends ChangeNotifier {
final CustomSemanticsAction action = CustomSemanticsAction.getAction(actionId)!;
builder.updateCustomAction(id: actionId, label: action.label, hint: action.hint, overrideId: action.action?.index ?? -1);
}
SemanticsBinding.instance!.window.updateSemantics(builder.build());
SemanticsBinding.instance.window.updateSemantics(builder.build());
notifyListeners();
}

View File

@ -219,7 +219,7 @@ class PlatformAssetBundle extends CachingAssetBundle {
Future<ByteData> load(String key) async {
final Uint8List encoded = utf8.encoder.convert(Uri(path: Uri.encodeFull(key)).path);
final ByteData? asset =
await ServicesBinding.instance!.defaultBinaryMessenger.send('flutter/assets', encoded.buffer.asByteData());
await ServicesBinding.instance.defaultBinaryMessenger.send('flutter/assets', encoded.buffer.asByteData());
if (asset == null)
throw FlutterError('Unable to load asset: $key');
return asset;

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
@ -39,7 +38,11 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
}
/// The current [ServicesBinding], if one has been created.
static ServicesBinding? get instance => _instance;
///
/// Provides access to the features exposed by this mixin. The binding must
/// be initialized before using this getter; this is typically done by calling
/// [runApp] or [WidgetsFlutterBinding.ensureInitialized].
static ServicesBinding get instance => BindingBase.checkInstance(_instance);
static ServicesBinding? _instance;
/// The default instance of [BinaryMessenger].

View File

@ -45,7 +45,7 @@ class BasicMessageChannel<T> {
final MessageCodec<T> codec;
/// The messenger which sends the bytes for this channel, not null.
BinaryMessenger get binaryMessenger => _binaryMessenger ?? ServicesBinding.instance!.defaultBinaryMessenger;
BinaryMessenger get binaryMessenger => _binaryMessenger ?? ServicesBinding.instance.defaultBinaryMessenger;
final BinaryMessenger? _binaryMessenger;
/// Sends the specified [message] to the platform plugins on this channel.
@ -118,7 +118,7 @@ class MethodChannel {
/// The messenger used by this channel to send platform messages.
///
/// The messenger may not be null.
BinaryMessenger get binaryMessenger => _binaryMessenger ?? ServicesBinding.instance!.defaultBinaryMessenger;
BinaryMessenger get binaryMessenger => _binaryMessenger ?? ServicesBinding.instance.defaultBinaryMessenger;
final BinaryMessenger? _binaryMessenger;
/// Backend implementation of [invokeMethod].
@ -450,7 +450,7 @@ class EventChannel {
final MethodCodec codec;
/// The messenger used by this channel to send platform messages, not null.
BinaryMessenger get binaryMessenger => _binaryMessenger ?? ServicesBinding.instance!.defaultBinaryMessenger;
BinaryMessenger get binaryMessenger => _binaryMessenger ?? ServicesBinding.instance.defaultBinaryMessenger;
final BinaryMessenger? _binaryMessenger;
/// Sets up a broadcast stream for receiving events on this channel.

View File

@ -264,7 +264,7 @@ class RestorationManager extends ChangeNotifier {
_isReplacing = _rootBucketIsValid && enabled;
if (_isReplacing) {
SchedulerBinding.instance!.addPostFrameCallback((Duration _) {
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
_isReplacing = false;
});
}
@ -350,7 +350,7 @@ class RestorationManager extends ChangeNotifier {
_bucketsNeedingSerialization.add(bucket);
if (!_serializationScheduled) {
_serializationScheduled = true;
SchedulerBinding.instance!.addPostFrameCallback((Duration _) => _doSerialization());
SchedulerBinding.instance.addPostFrameCallback((Duration _) => _doSerialization());
}
}
@ -413,7 +413,7 @@ class RestorationManager extends ChangeNotifier {
/// current restoration data is directly sent to the engine.
void flushData() {
assert(!_debugDoingUpdate);
if (SchedulerBinding.instance!.hasScheduledFrame) {
if (SchedulerBinding.instance.hasScheduledFrame) {
return;
}
_doSerialization();

View File

@ -502,7 +502,7 @@ class SystemChrome {
/// [SystemUiMode.leanBack].
///
static Future<void> setSystemUIChangeCallback(SystemUiChangeCallback? callback) async {
ServicesBinding.instance!.setSystemUiChangeCallback(callback);
ServicesBinding.instance.setSystemUiChangeCallback(callback);
// Skip setting up the listener if there is no callback.
if (callback != null) {
await SystemChannels.platform.invokeMethod<void>(

View File

@ -1324,7 +1324,7 @@ class _FocusableActionDetectorState extends State<FocusableActionDetector> {
@override
void initState() {
super.initState();
SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
_updateHighlightMode(FocusManager.instance.highlightMode);
});
FocusManager.instance.addHighlightModeListener(_handleFocusHighlightModeChange);
@ -1413,7 +1413,7 @@ class _FocusableActionDetectorState extends State<FocusableActionDetector> {
return _focused && _canShowHighlight && canRequestFocus(target);
}
assert(SchedulerBinding.instance!.schedulerPhase != SchedulerPhase.persistentCallbacks);
assert(SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks);
final FocusableActionDetector oldTarget = oldWidget ?? widget;
final bool didShowHoverHighlight = shouldShowHoverHighlight(oldTarget);
final bool didShowFocusHighlight = shouldShowFocusHighlight(oldTarget);
@ -1434,7 +1434,7 @@ class _FocusableActionDetectorState extends State<FocusableActionDetector> {
void didUpdateWidget(FocusableActionDetector oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.enabled != oldWidget.enabled) {
SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
_mayTriggerCallback(oldWidget: oldWidget);
});
}

View File

@ -1257,16 +1257,16 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
// If window.defaultRouteName isn't '/', we should assume it was set
// intentionally via `setInitialRoute`, and should override whatever is in
// [widget.initialRoute].
String get _initialRouteName => WidgetsBinding.instance!.window.defaultRouteName != Navigator.defaultRouteName
? WidgetsBinding.instance!.window.defaultRouteName
: widget.initialRoute ?? WidgetsBinding.instance!.window.defaultRouteName;
String get _initialRouteName => WidgetsBinding.instance.window.defaultRouteName != Navigator.defaultRouteName
? WidgetsBinding.instance.window.defaultRouteName
: widget.initialRoute ?? WidgetsBinding.instance.window.defaultRouteName;
@override
void initState() {
super.initState();
_updateRouting();
_locale = _resolveLocales(WidgetsBinding.instance!.window.locales, widget.supportedLocales);
WidgetsBinding.instance!.addObserver(this);
_locale = _resolveLocales(WidgetsBinding.instance.window.locales, widget.supportedLocales);
WidgetsBinding.instance.addObserver(this);
}
@override
@ -1277,7 +1277,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
@override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
WidgetsBinding.instance.removeObserver(this);
_defaultRouteInformationProvider?.dispose();
super.dispose();
}
@ -1681,7 +1681,7 @@ class _MediaQueryFromWindowsState extends State<_MediaQueryFromWindow> with Widg
@override
void initState() {
super.initState();
WidgetsBinding.instance!.addObserver(this);
WidgetsBinding.instance.addObserver(this);
}
// ACCESSIBILITY
@ -1725,7 +1725,7 @@ class _MediaQueryFromWindowsState extends State<_MediaQueryFromWindow> with Widg
@override
Widget build(BuildContext context) {
MediaQueryData data = MediaQueryData.fromWindow(WidgetsBinding.instance!.window);
MediaQueryData data = MediaQueryData.fromWindow(WidgetsBinding.instance.window);
if (!kReleaseMode) {
data = data.copyWith(platformBrightness: debugBrightnessOverride);
}
@ -1737,7 +1737,7 @@ class _MediaQueryFromWindowsState extends State<_MediaQueryFromWindow> with Widg
@override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}

View File

@ -893,7 +893,7 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
AutocompletePreviousOptionIntent: _previousOptionAction,
AutocompleteNextOptionIntent: _nextOptionAction,
};
SchedulerBinding.instance!.addPostFrameCallback((Duration _) {
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
_updateOverlay();
});
}
@ -906,7 +906,7 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
widget.textEditingController,
);
_updateFocusNode(oldWidget.focusNode, widget.focusNode);
SchedulerBinding.instance!.addPostFrameCallback((Duration _) {
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
_updateOverlay();
});
}

View File

@ -89,7 +89,7 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
// If the child doesn't exist yet, we got called during the very first
// build of this subtree. Wait until the end of the frame to update
// the child when the child is guaranteed to be present.
SchedulerBinding.instance!.addPostFrameCallback((Duration timeStamp) {
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
if (!mounted) {
return;
}
@ -155,7 +155,7 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
}());
_handles!.remove(handle);
if (_handles!.isEmpty) {
if (SchedulerBinding.instance!.schedulerPhase.index < SchedulerPhase.persistentCallbacks.index) {
if (SchedulerBinding.instance.schedulerPhase.index < SchedulerPhase.persistentCallbacks.index) {
// Build/layout haven't started yet so let's just schedule this for
// the next frame.
setState(() { _keepingAlive = false; });

View File

@ -69,7 +69,7 @@ class BannerPainter extends CustomPainter {
assert(location != null),
assert(color != null),
assert(textStyle != null),
super(repaint: PaintingBinding.instance!.systemFonts);
super(repaint: PaintingBinding.instance.systemFonts);
/// The message to show in the banner.
final String message;

View File

@ -50,12 +50,12 @@ export 'dart:ui' show AppLifecycleState, Locale;
/// @override
/// void initState() {
/// super.initState();
/// WidgetsBinding.instance!.addObserver(this);
/// WidgetsBinding.instance.addObserver(this);
/// }
///
/// @override
/// void dispose() {
/// WidgetsBinding.instance!.removeObserver(this);
/// WidgetsBinding.instance.removeObserver(this);
/// super.dispose();
/// }
///
@ -147,19 +147,19 @@ abstract class WidgetsBindingObserver {
/// @override
/// void initState() {
/// super.initState();
/// _lastSize = WidgetsBinding.instance!.window.physicalSize;
/// WidgetsBinding.instance!.addObserver(this);
/// _lastSize = WidgetsBinding.instance.window.physicalSize;
/// WidgetsBinding.instance.addObserver(this);
/// }
///
/// @override
/// void dispose() {
/// WidgetsBinding.instance!.removeObserver(this);
/// WidgetsBinding.instance.removeObserver(this);
/// super.dispose();
/// }
///
/// @override
/// void didChangeMetrics() {
/// setState(() { _lastSize = WidgetsBinding.instance!.window.physicalSize; });
/// setState(() { _lastSize = WidgetsBinding.instance.window.physicalSize; });
/// }
///
/// @override
@ -203,12 +203,12 @@ abstract class WidgetsBindingObserver {
/// @override
/// void initState() {
/// super.initState();
/// WidgetsBinding.instance!.addObserver(this);
/// WidgetsBinding.instance.addObserver(this);
/// }
///
/// @override
/// void dispose() {
/// WidgetsBinding.instance!.removeObserver(this);
/// WidgetsBinding.instance.removeObserver(this);
/// super.dispose();
/// }
///
@ -216,7 +216,7 @@ abstract class WidgetsBindingObserver {
///
/// @override
/// void didChangeTextScaleFactor() {
/// setState(() { _lastTextScaleFactor = WidgetsBinding.instance!.window.textScaleFactor; });
/// setState(() { _lastTextScaleFactor = WidgetsBinding.instance.window.textScaleFactor; });
/// }
///
/// @override
@ -296,6 +296,14 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
}());
}
/// The current [WidgetsBinding], if one has been created.
///
/// Provides access to the features exposed by this mixin. The binding must
/// be initialized before using this getter; this is typically done by calling
/// [runApp] or [WidgetsFlutterBinding.ensureInitialized].
static WidgetsBinding get instance => BindingBase.checkInstance(_instance);
static WidgetsBinding? _instance;
void _debugAddStackFilters() {
const PartialStackFrame elementInflateWidget = PartialStackFrame(package: 'package:flutter/src/widgets/framework.dart', className: 'Element', method: 'inflateWidget');
const PartialStackFrame elementUpdateChild = PartialStackFrame(package: 'package:flutter/src/widgets/framework.dart', className: 'Element', method: 'updateChild');
@ -377,14 +385,6 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
));
}
/// The current [WidgetsBinding], if one has been created.
///
/// If you need the binding to be constructed before calling [runApp],
/// you can ensure a Widget binding has been constructed by calling the
/// `WidgetsFlutterBinding.ensureInitialized()` function.
static WidgetsBinding? get instance => _instance;
static WidgetsBinding? _instance;
@override
void initServiceExtensions() {
super.initServiceExtensions();
@ -862,14 +862,14 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
developer.Timeline.instantSync('Rasterized first useful frame');
developer.postEvent('Flutter.FirstFrame', <String, dynamic>{});
}
SchedulerBinding.instance!.removeTimingsCallback(firstFrameCallback!);
SchedulerBinding.instance.removeTimingsCallback(firstFrameCallback!);
firstFrameCallback = null;
_firstFrameCompleter.complete();
};
// Callback is only invoked when FlutterView.render is called. When
// sendFramesToEngine is set to false during the frame, it will not be
// called and we need to remove the callback (see below).
SchedulerBinding.instance!.addTimingsCallback(firstFrameCallback!);
SchedulerBinding.instance.addTimingsCallback(firstFrameCallback!);
}
try {
@ -893,7 +893,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
// This frame is deferred and not the first frame sent to the engine that
// should be reported.
_needToReportFirstFrame = true;
SchedulerBinding.instance!.removeTimingsCallback(firstFrameCallback!);
SchedulerBinding.instance.removeTimingsCallback(firstFrameCallback!);
}
}
@ -938,7 +938,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
child: rootWidget,
).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);
if (isBootstrapFrame) {
SchedulerBinding.instance!.ensureVisualUpdate();
SchedulerBinding.instance.ensureVisualUpdate();
}
}
@ -1033,12 +1033,11 @@ void runApp(Widget app) {
}
String _debugDumpAppString() {
assert(WidgetsBinding.instance != null);
const String mode = kDebugMode ? 'DEBUG MODE' : 'PROFILE MODE';
const String mode = kDebugMode ? 'DEBUG MODE' : kReleaseMode ? 'RELEASE MODE' : 'PROFILE MODE';
final StringBuffer buffer = StringBuffer();
buffer.writeln('${WidgetsBinding.instance.runtimeType} - $mode');
if (WidgetsBinding.instance!.renderViewElement != null) {
buffer.writeln(WidgetsBinding.instance!.renderViewElement!.toStringDeep());
if (WidgetsBinding.instance.renderViewElement != null) {
buffer.writeln(WidgetsBinding.instance.renderViewElement!.toStringDeep());
} else {
buffer.writeln('<no tree currently mounted>');
}
@ -1047,8 +1046,7 @@ String _debugDumpAppString() {
/// Print a string representation of the currently running app.
void debugDumpApp() {
final String value = _debugDumpAppString();
debugPrint(value);
debugPrint(_debugDumpAppString());
}
/// A bridge from a [RenderObject] to an [Element] tree.
@ -1229,22 +1227,34 @@ class RenderObjectToWidgetElement<T extends RenderObject> extends RootRenderObje
/// A concrete binding for applications based on the Widgets framework.
///
/// This is the glue that binds the framework to the Flutter engine.
///
/// When using the widgets framework, this binding, or one that
/// implements the same interfaces, must be used. The following
/// mixins are used to implement this binding:
///
/// * [GestureBinding], which implements the basics of hit testing.
/// * [SchedulerBinding], which introduces the concepts of frames.
/// * [ServicesBinding], which provides access to the plugin subsystem.
/// * [PaintingBinding], which enables decoding images.
/// * [SemanticsBinding], which supports accessibility.
/// * [RendererBinding], which handles the render tree.
/// * [WidgetsBinding], which handles the widget tree.
class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
/// Returns an instance of the [WidgetsBinding], creating and
/// initializing it if necessary. If one is created, it will be a
/// [WidgetsFlutterBinding]. If one was previously initialized, then
/// it will at least implement [WidgetsBinding].
/// Returns an instance of the binding that implements
/// [WidgetsBinding]. If no binding has yet been initialized, the
/// [WidgetsFlutterBinding] class is used to create and initialize
/// one.
///
/// You only need to call this method if you need the binding to be
/// initialized before calling [runApp].
///
/// In the `flutter_test` framework, [testWidgets] initializes the
/// binding instance to a [TestWidgetsFlutterBinding], not a
/// [WidgetsFlutterBinding].
/// [WidgetsFlutterBinding]. See
/// [TestWidgetsFlutterBinding.ensureInitialized].
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
if (WidgetsBinding._instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance!;
return WidgetsBinding.instance;
}
}

View File

@ -919,7 +919,7 @@ class _DragAvatar<T extends Object> extends Drag {
_lastOffset = globalPosition - dragStartPoint;
_entry!.markNeedsBuild();
final HitTestResult result = HitTestResult();
WidgetsBinding.instance!.hitTest(result, globalPosition + feedbackOffset);
WidgetsBinding.instance.hitTest(result, globalPosition + feedbackOffset);
final List<_DragTargetState<Object>> targets = _getDragTargets(result.path).toList();

View File

@ -1625,7 +1625,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
if (!_didAutoFocus && widget.autofocus) {
_didAutoFocus = true;
SchedulerBinding.instance!.addPostFrameCallback((_) {
SchedulerBinding.instance.addPostFrameCallback((_) {
if (mounted) {
FocusScope.of(context).autofocus(widget.focusNode);
}
@ -1700,7 +1700,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_selectionOverlay = null;
_focusAttachment!.detach();
widget.focusNode.removeListener(_handleFocusChanged);
WidgetsBinding.instance!.removeObserver(this);
WidgetsBinding.instance.removeObserver(this);
_clipboardStatus?.removeListener(_onChangedClipboardStatus);
_clipboardStatus?.dispose();
super.dispose();
@ -2219,7 +2219,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
return;
}
_showCaretOnScreenScheduled = true;
SchedulerBinding.instance!.addPostFrameCallback((Duration _) {
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
_showCaretOnScreenScheduled = false;
if (_currentCaretRect == null || !_scrollController!.hasClients) {
return;
@ -2272,10 +2272,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
@override
void didChangeMetrics() {
if (_lastBottomViewInset < WidgetsBinding.instance!.window.viewInsets.bottom) {
if (_lastBottomViewInset < WidgetsBinding.instance.window.viewInsets.bottom) {
_scheduleShowCaretOnScreen();
}
_lastBottomViewInset = WidgetsBinding.instance!.window.viewInsets.bottom;
_lastBottomViewInset = WidgetsBinding.instance.window.viewInsets.bottom;
}
@pragma('vm:notify-debugger-on-exception')
@ -2432,8 +2432,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_updateOrDisposeSelectionOverlayIfNeeded();
if (_hasFocus) {
// Listen for changing viewInsets, which indicates keyboard showing up.
WidgetsBinding.instance!.addObserver(this);
_lastBottomViewInset = WidgetsBinding.instance!.window.viewInsets.bottom;
WidgetsBinding.instance.addObserver(this);
_lastBottomViewInset = WidgetsBinding.instance.window.viewInsets.bottom;
if (!widget.readOnly) {
_scheduleShowCaretOnScreen();
}
@ -2442,7 +2442,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_handleSelectionChanged(TextSelection.collapsed(offset: _value.text.length), null);
}
} else {
WidgetsBinding.instance!.removeObserver(this);
WidgetsBinding.instance.removeObserver(this);
// Clear the selection and composition state if this widget lost focus.
_value = TextEditingValue(text: _value.text);
_currentPromptRectRange = null;
@ -2455,8 +2455,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
final Size size = renderEditable.size;
final Matrix4 transform = renderEditable.getTransformTo(null);
_textInputConnection!.setEditableSizeAndTransform(size, transform);
SchedulerBinding.instance!
.addPostFrameCallback((Duration _) => _updateSizeAndTransform());
SchedulerBinding.instance.addPostFrameCallback((Duration _) => _updateSizeAndTransform());
}
}
@ -2478,8 +2477,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
assert(composingRect != null);
_textInputConnection!.setComposingRect(composingRect);
SchedulerBinding.instance!
.addPostFrameCallback((Duration _) => _updateComposingRectIfNeeded());
SchedulerBinding.instance.addPostFrameCallback((Duration _) => _updateComposingRectIfNeeded());
}
}
@ -2491,8 +2489,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
final Rect caretRect = renderEditable.getLocalRectForCaret(currentTextPosition);
_textInputConnection!.setCaretRect(caretRect);
}
SchedulerBinding.instance!
.addPostFrameCallback((Duration _) => _updateCaretRectIfNeeded());
SchedulerBinding.instance.addPostFrameCallback((Duration _) => _updateCaretRectIfNeeded());
}
}

View File

@ -1465,21 +1465,21 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
void registerGlobalHandlers() {
assert(RawKeyboard.instance.keyEventHandler == null);
RawKeyboard.instance.keyEventHandler = _handleRawKeyEvent;
GestureBinding.instance!.pointerRouter.addGlobalRoute(_handlePointerEvent);
GestureBinding.instance.pointerRouter.addGlobalRoute(_handlePointerEvent);
}
@override
void dispose() {
if (RawKeyboard.instance.keyEventHandler == _handleRawKeyEvent) {
RawKeyboard.instance.keyEventHandler = null;
GestureBinding.instance!.pointerRouter.removeGlobalRoute(_handlePointerEvent);
GestureBinding.instance.pointerRouter.removeGlobalRoute(_handlePointerEvent);
}
super.dispose();
}
/// Provides convenient access to the current [FocusManager] singleton from
/// the [WidgetsBinding] instance.
static FocusManager get instance => WidgetsBinding.instance!.focusManager;
static FocusManager get instance => WidgetsBinding.instance.focusManager;
/// Sets the strategy by which [highlightMode] is determined.
///
@ -1522,7 +1522,7 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.iOS:
if (WidgetsBinding.instance!.mouseTracker.mouseIsConnected) {
if (WidgetsBinding.instance.mouseTracker.mouseIsConnected) {
return FocusHighlightMode.traditional;
}
return FocusHighlightMode.touch;
@ -1821,7 +1821,7 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
/// Provides convenient access to the current [FocusManager.primaryFocus] from the
/// [WidgetsBinding] instance.
FocusNode? get primaryFocus => WidgetsBinding.instance!.focusManager.primaryFocus;
FocusNode? get primaryFocus => WidgetsBinding.instance.focusManager.primaryFocus;
/// Returns a text representation of the current focus tree, along with the
/// current attributes on each node.

View File

@ -149,7 +149,7 @@ abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
/// constructor.
const GlobalKey.constructor() : super.empty();
Element? get _currentElement => WidgetsBinding.instance!.buildOwner!._globalKeyRegistry[this];
Element? get _currentElement => WidgetsBinding.instance.buildOwner!._globalKeyRegistry[this];
/// The build context in which the widget with this key builds.
///

View File

@ -930,7 +930,7 @@ class HeroController extends NavigatorObserver {
// going to end up, and the `to` route will go back onstage.
to.offstage = to.animation!.value == 0.0;
WidgetsBinding.instance!.addPostFrameCallback((Duration value) {
WidgetsBinding.instance.addPostFrameCallback((Duration value) {
_startHeroTransition(from, to, animation, flightType, isUserGestureTransition);
});
}

View File

@ -119,7 +119,7 @@ Future<void> precacheImage(
// Give callers until at least the end of the frame to subscribe to the
// image stream.
// See ImageCache._liveImages
SchedulerBinding.instance!.addPostFrameCallback((Duration timeStamp) {
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
stream.removeListener(listener!);
});
},
@ -1118,14 +1118,14 @@ class _ImageState extends State<Image> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance!.addObserver(this);
WidgetsBinding.instance.addObserver(this);
_scrollAwareContext = DisposableBuildContext<State<Image>>(this);
}
@override
void dispose() {
assert(_imageStream != null);
WidgetsBinding.instance!.removeObserver(this);
WidgetsBinding.instance.removeObserver(this);
_stopListeningToStream();
_completerHandle?.dispose();
_scrollAwareContext.dispose();
@ -1175,7 +1175,7 @@ class _ImageState extends State<Image> with WidgetsBindingObserver {
void _updateInvertColors() {
_invertColors = MediaQuery.maybeOf(context)?.invertColors
?? SemanticsBinding.instance!.accessibilityFeatures.invertColors;
?? SemanticsBinding.instance.accessibilityFeatures.invertColors;
}
void _resolveImage() {

View File

@ -759,7 +759,7 @@ class _ListWheelScrollViewState extends State<ListWheelScrollView> {
super.didUpdateWidget(oldWidget);
if (widget.controller != null && widget.controller != scrollController) {
final ScrollController? oldScrollController = scrollController;
SchedulerBinding.instance!.addPostFrameCallback((_) {
SchedulerBinding.instance.addPostFrameCallback((_) {
oldScrollController!.dispose();
});
scrollController = widget.controller;

View File

@ -543,7 +543,7 @@ class _LocalizationsState extends State<Localizations> {
// have finished loading. Until then the old locale will continue to be used.
// - If we're running at app startup time then defer reporting the first
// "useful" frame until after the async load has completed.
RendererBinding.instance!.deferFirstFrame();
RendererBinding.instance.deferFirstFrame();
typeToResourcesFuture.then<void>((Map<Type, dynamic> value) {
if (mounted) {
setState(() {
@ -551,7 +551,7 @@ class _LocalizationsState extends State<Localizations> {
_locale = locale;
});
}
RendererBinding.instance!.allowFirstFrame();
RendererBinding.instance.allowFirstFrame();
});
}
}

View File

@ -3513,7 +3513,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
// controller at the end of the build.
if (newHeroController.navigator != null) {
final NavigatorState previousOwner = newHeroController.navigator!;
ServicesBinding.instance!.addPostFrameCallback((Duration timestamp) {
ServicesBinding.instance.addPostFrameCallback((Duration timestamp) {
// We only check if this navigator still owns the hero controller.
if (_heroControllerFromScope == newHeroController) {
final bool hasHeroControllerOwnerShip = _heroControllerFromScope!._navigator == this;
@ -5319,7 +5319,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
void _cancelActivePointers() {
// TODO(abarth): This mechanism is far from perfect. See https://github.com/flutter/flutter/issues/4770
if (SchedulerBinding.instance!.schedulerPhase == SchedulerPhase.idle) {
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle) {
// If we're between frames (SchedulerPhase.idle) then absorb any
// subsequent pointers from this frame. The absorbing flag will be
// reset in the next frame, see build().
@ -5330,7 +5330,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
// to false on the next frame.
});
}
_activePointers.toList().forEach(WidgetsBinding.instance!.cancelPointer);
_activePointers.toList().forEach(WidgetsBinding.instance.cancelPointer);
}
@override

View File

@ -1332,7 +1332,7 @@ class _NestedScrollController extends ScrollController {
// the position change notifications because those happen synchronously
// during a frame, at a time where it's too late to call setState. Since the
// result is usually animated, the lag incurred is no big deal.
SchedulerBinding.instance!.addPostFrameCallback(
SchedulerBinding.instance.addPostFrameCallback(
(Duration timeStamp) {
coordinator.updateShadow();
},

View File

@ -151,8 +151,8 @@ class OverlayEntry extends ChangeNotifier {
return;
overlay._entries.remove(this);
if (SchedulerBinding.instance!.schedulerPhase == SchedulerPhase.persistentCallbacks) {
SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) {
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
overlay._markDirty();
});
} else {

View File

@ -627,7 +627,7 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
item.dragging = true;
item.rebuild();
_dragStartTransitionComplete = false;
SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
_dragStartTransitionComplete = true;
});

View File

@ -275,18 +275,18 @@ class _RootRestorationScopeState extends State<RootRestorationScope> {
void _loadRootBucketIfNecessary() {
if (_isWaitingForRootBucket && !_isLoadingRootBucket) {
_isLoadingRootBucket = true;
RendererBinding.instance!.deferFirstFrame();
ServicesBinding.instance!.restorationManager.rootBucket.then((RestorationBucket? bucket) {
RendererBinding.instance.deferFirstFrame();
ServicesBinding.instance.restorationManager.rootBucket.then((RestorationBucket? bucket) {
_isLoadingRootBucket = false;
if (mounted) {
ServicesBinding.instance!.restorationManager.addListener(_replaceRootBucket);
ServicesBinding.instance.restorationManager.addListener(_replaceRootBucket);
setState(() {
_rootBucket = bucket;
_rootBucketValid = true;
_okToRenderBlankContainer = false;
});
}
RendererBinding.instance!.allowFirstFrame();
RendererBinding.instance.allowFirstFrame();
});
}
}
@ -294,7 +294,7 @@ class _RootRestorationScopeState extends State<RootRestorationScope> {
void _replaceRootBucket() {
_rootBucketValid = false;
_rootBucket = null;
ServicesBinding.instance!.restorationManager.removeListener(_replaceRootBucket);
ServicesBinding.instance.restorationManager.removeListener(_replaceRootBucket);
_loadRootBucketIfNecessary();
assert(!_isWaitingForRootBucket); // Ensure that load finished synchronously.
}
@ -302,7 +302,7 @@ class _RootRestorationScopeState extends State<RootRestorationScope> {
@override
void dispose() {
if (_rootBucketValid) {
ServicesBinding.instance!.restorationManager.removeListener(_replaceRootBucket);
ServicesBinding.instance.restorationManager.removeListener(_replaceRootBucket);
}
super.dispose();
}

View File

@ -504,7 +504,7 @@ class _RouterState<T> extends State<Router<T>> with RestorationMixin {
return;
assert(_currentIntentionToReport != _IntentionToReportRouteInformation.none);
_routeInformationReportingTaskScheduled = true;
SchedulerBinding.instance!.addPostFrameCallback(_reportRouteInformation);
SchedulerBinding.instance.addPostFrameCallback(_reportRouteInformation);
}
void _reportRouteInformation(Duration timestamp) {
@ -962,7 +962,7 @@ class RootBackButtonDispatcher extends BackButtonDispatcher with WidgetsBindingO
@override
void addCallback(ValueGetter<Future<bool>> callback) {
if (!hasCallbacks)
WidgetsBinding.instance!.addObserver(this);
WidgetsBinding.instance.addObserver(this);
super.addCallback(callback);
}
@ -970,7 +970,7 @@ class RootBackButtonDispatcher extends BackButtonDispatcher with WidgetsBindingO
void removeCallback(ValueGetter<Future<bool>> callback) {
super.removeCallback(callback);
if (!hasCallbacks)
WidgetsBinding.instance!.removeObserver(this);
WidgetsBinding.instance.removeObserver(this);
}
@override
@ -1356,7 +1356,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid
@override
void addListener(VoidCallback listener) {
if (!hasListeners)
WidgetsBinding.instance!.addObserver(this);
WidgetsBinding.instance.addObserver(this);
super.addListener(listener);
}
@ -1364,7 +1364,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid
void removeListener(VoidCallback listener) {
super.removeListener(listener);
if (!hasListeners)
WidgetsBinding.instance!.removeObserver(this);
WidgetsBinding.instance.removeObserver(this);
}
@override
@ -1374,7 +1374,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid
// is no longer being used, there's no listener, and so it will get garbage
// collected.
if (hasListeners)
WidgetsBinding.instance!.removeObserver(this);
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

View File

@ -616,11 +616,11 @@ mixin LocalHistoryRoute<T> on Route<T> {
entry._owner = null;
entry._notifyRemoved();
if (_localHistory!.isEmpty) {
if (SchedulerBinding.instance!.schedulerPhase == SchedulerPhase.persistentCallbacks) {
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) {
// The local history might be removed as a result of disposing inactive
// elements during finalizeTree. The state is locked at this moment, and
// we can only notify state has changed in the next frame.
SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
changedInternalState();
});
} else {

View File

@ -83,7 +83,7 @@ class ScrollAwareImageProvider<T extends Object> extends ImageProvider<T> {
// Do this before checking scrolling, so that if the bytes are available we
// render them even though we're scrolling fast - there's no additional
// allocations to do for texture memory, it's already there.
if (stream.completer != null || PaintingBinding.instance!.imageCache!.containsKey(key)) {
if (stream.completer != null || PaintingBinding.instance.imageCache.containsKey(key)) {
imageProvider.resolveStreamForKey(configuration, stream, key, handleError);
return;
}
@ -96,7 +96,7 @@ class ScrollAwareImageProvider<T extends Object> extends ImageProvider<T> {
// Try to get to end of the frame callbacks of the next frame, and then
// check again.
if (Scrollable.recommendDeferredLoadingForContext(context.context!)) {
SchedulerBinding.instance!.scheduleFrameCallback((_) {
SchedulerBinding.instance.scheduleFrameCallback((Duration timeStamp) {
scheduleMicrotask(() => resolveStreamForKey(configuration, stream, key, handleError));
});
return;

View File

@ -224,7 +224,7 @@ class ScrollPhysics {
assert(metrics != null);
assert(context != null);
if (parent == null) {
final double maxPhysicalPixels = WidgetsBinding.instance!.window.physicalSize.longestSide;
final double maxPhysicalPixels = WidgetsBinding.instance.window.physicalSize.longestSide;
return velocity.abs() > maxPhysicalPixels;
}
return parent!.recommendDeferredLoading(velocity, metrics, context);
@ -356,8 +356,8 @@ class ScrollPhysics {
static final Tolerance _kDefaultTolerance = Tolerance(
// TODO(ianh): Handle the case of the device pixel ratio changing.
// TODO(ianh): Get this from the local MediaQuery not dart:ui's window object.
velocity: 1.0 / (0.050 * WidgetsBinding.instance!.window.devicePixelRatio), // logical pixels per second
distance: 1.0 / WidgetsBinding.instance!.window.devicePixelRatio, // logical pixels
velocity: 1.0 / (0.050 * WidgetsBinding.instance.window.devicePixelRatio), // logical pixels per second
distance: 1.0 / WidgetsBinding.instance.window.devicePixelRatio, // logical pixels
);
/// The tolerance to use for ballistic simulations.

View File

@ -254,7 +254,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
/// If there is any overscroll, it is reported using [didOverscrollBy].
double setPixels(double newPixels) {
assert(hasPixels);
assert(SchedulerBinding.instance!.schedulerPhase != SchedulerPhase.persistentCallbacks, "A scrollable's position should not change during the build, layout, and paint phases, otherwise the rendering will be confused.");
assert(SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks, "A scrollable's position should not change during the build, layout, and paint phases, otherwise the rendering will be confused.");
if (newPixels != pixels) {
final double overscroll = applyBoundaryConditions(newPixels);
assert(() {
@ -375,7 +375,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
_impliedVelocity = value - pixels;
_pixels = value;
notifyListeners();
SchedulerBinding.instance!.addPostFrameCallback((Duration timeStamp) {
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
_impliedVelocity = 0;
});
}

View File

@ -440,7 +440,7 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
_persistedScrollOffset.value = offset;
// [saveOffset] is called after a scrolling ends and it is usually not
// followed by a frame. Therefore, manually flush restoration data.
ServicesBinding.instance!.restorationManager.flushData();
ServicesBinding.instance.restorationManager.flushData();
}
@override
@ -705,7 +705,7 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
final double targetScrollOffset = _targetScrollOffsetForPointerScroll(delta);
// Only express interest in the event if it would actually result in a scroll.
if (delta != 0.0 && targetScrollOffset != position.pixels) {
GestureBinding.instance!.pointerSignalResolver.register(event, _handlePointerScroll);
GestureBinding.instance.pointerSignalResolver.register(event, _handlePointerScroll);
}
}
}

Some files were not shown because too many files have changed in this diff Show More