mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Reverse dependency between services and scheduler (#54212)
This commit is contained in:
parent
090fc5cc53
commit
d47ad7ec0d
@ -736,8 +736,8 @@ abstract class FrameRecorder {
|
||||
class _RecordingWidgetsBinding extends BindingBase
|
||||
with
|
||||
GestureBinding,
|
||||
ServicesBinding,
|
||||
SchedulerBinding,
|
||||
ServicesBinding,
|
||||
PaintingBinding,
|
||||
SemanticsBinding,
|
||||
RendererBinding,
|
||||
|
@ -5,7 +5,7 @@
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
@ -48,7 +48,7 @@ class _LifeCycleSpyState extends State<LifeCycleSpy> with WidgetsBindingObserver
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
_actualLifeCycleSequence = <AppLifecycleState>[
|
||||
SchedulerBinding.instance.lifecycleState
|
||||
ServicesBinding.instance.lifecycleState
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import 'dart:async';
|
||||
import 'dart:convert' show json;
|
||||
import 'dart:developer' as developer;
|
||||
import 'dart:io' show exit;
|
||||
import 'dart:ui' as ui show saveCompilationTrace, Window, window;
|
||||
import 'dart:ui' as ui show AppLifecycleState, saveCompilationTrace, Window, window;
|
||||
// Before adding any more dart:ui imports, please read the README.
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
@ -552,6 +552,29 @@ abstract class BindingBase {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO(goderbauer): Remove the next two members after the service/scheduler dependencies
|
||||
// have been turned around.
|
||||
|
||||
/// Whether the application is visible, and if so, whether it is currently
|
||||
/// interactive.
|
||||
///
|
||||
/// This is set by [handleAppLifecycleStateChanged] when the
|
||||
/// [SystemChannels.lifecycle] notification is dispatched.
|
||||
///
|
||||
/// The preferred way to watch for changes to this value is using
|
||||
/// [WidgetsBindingObserver.didChangeAppLifecycleState].
|
||||
ui.AppLifecycleState get lifecycleState => null;
|
||||
|
||||
/// Called when the application lifecycle state changes.
|
||||
///
|
||||
/// Notifies all the observers using
|
||||
/// [WidgetsBindingObserver.didChangeAppLifecycleState].
|
||||
///
|
||||
/// This method exposes notifications from [SystemChannels.lifecycle].
|
||||
@protected
|
||||
@mustCallSuper
|
||||
void handleAppLifecycleStateChanged(ui.AppLifecycleState state) { }
|
||||
|
||||
@override
|
||||
String toString() => '<${objectRuntimeType(this, 'BindingBase')}>';
|
||||
}
|
||||
|
@ -467,7 +467,7 @@ void debugDumpSemanticsTree(DebugSemanticsDumpOrder childOrder) {
|
||||
/// 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.
|
||||
class RenderingFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, SemanticsBinding, PaintingBinding, RendererBinding {
|
||||
class RenderingFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, SemanticsBinding, PaintingBinding, RendererBinding {
|
||||
/// Creates a binding for the rendering layer.
|
||||
///
|
||||
/// The `root` render box is attached directly to the [renderView] and is
|
||||
|
@ -9,7 +9,6 @@ import 'dart:ui' show AppLifecycleState, FramePhase, FrameTiming, TimingsCallbac
|
||||
|
||||
import 'package:collection/collection.dart' show PriorityQueue, HeapPriorityQueue;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'debug.dart';
|
||||
import 'priority.dart';
|
||||
@ -197,13 +196,11 @@ enum SchedulerPhase {
|
||||
/// * Non-rendering tasks, to be run between frames. These are given a
|
||||
/// priority and are executed in priority order according to a
|
||||
/// [schedulingStrategy].
|
||||
mixin SchedulerBinding on BindingBase, ServicesBinding {
|
||||
mixin SchedulerBinding on BindingBase {
|
||||
@override
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
_instance = this;
|
||||
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
|
||||
readInitialLifecycleStateFromNativeWindow();
|
||||
|
||||
if (!kReleaseMode) {
|
||||
int frameNumber = 0;
|
||||
@ -302,35 +299,19 @@ mixin SchedulerBinding on BindingBase, ServicesBinding {
|
||||
///
|
||||
/// The preferred way to watch for changes to this value is using
|
||||
/// [WidgetsBindingObserver.didChangeAppLifecycleState].
|
||||
@override
|
||||
AppLifecycleState get lifecycleState => _lifecycleState;
|
||||
AppLifecycleState _lifecycleState;
|
||||
|
||||
/// Initializes the [lifecycleState] with the [initialLifecycleState] from the
|
||||
/// window.
|
||||
///
|
||||
/// Once the [lifecycleState] is populated through any means (including this
|
||||
/// method), this method will do nothing. This is because the
|
||||
/// [initialLifecycleState] may already be stale and it no longer makes sense
|
||||
/// to use the initial state at dart vm startup as the current state anymore.
|
||||
///
|
||||
/// The latest state should be obtained by subscribing to
|
||||
/// [WidgetsBindingObserver.didChangeAppLifecycleState].
|
||||
@protected
|
||||
void readInitialLifecycleStateFromNativeWindow() {
|
||||
if (_lifecycleState == null && _parseAppLifecycleMessage(window.initialLifecycleState) != null) {
|
||||
_handleLifecycleMessage(window.initialLifecycleState);
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when the application lifecycle state changes.
|
||||
///
|
||||
/// Notifies all the observers using
|
||||
/// [WidgetsBindingObserver.didChangeAppLifecycleState].
|
||||
///
|
||||
/// This method exposes notifications from [SystemChannels.lifecycle].
|
||||
@protected
|
||||
@mustCallSuper
|
||||
@override
|
||||
void handleAppLifecycleStateChanged(AppLifecycleState state) {
|
||||
super.handleAppLifecycleStateChanged(state);
|
||||
assert(state != null);
|
||||
_lifecycleState = state;
|
||||
switch (state) {
|
||||
@ -345,25 +326,6 @@ mixin SchedulerBinding on BindingBase, ServicesBinding {
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> _handleLifecycleMessage(String message) async {
|
||||
handleAppLifecycleStateChanged(_parseAppLifecycleMessage(message));
|
||||
return null;
|
||||
}
|
||||
|
||||
static AppLifecycleState _parseAppLifecycleMessage(String message) {
|
||||
switch (message) {
|
||||
case 'AppLifecycleState.paused':
|
||||
return AppLifecycleState.paused;
|
||||
case 'AppLifecycleState.resumed':
|
||||
return AppLifecycleState.resumed;
|
||||
case 'AppLifecycleState.inactive':
|
||||
return AppLifecycleState.inactive;
|
||||
case 'AppLifecycleState.detached':
|
||||
return AppLifecycleState.detached;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// The strategy to use when deciding whether to run a task or not.
|
||||
///
|
||||
/// Defaults to [defaultSchedulingStrategy].
|
||||
|
@ -7,6 +7,7 @@ import 'dart:typed_data';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
|
||||
import 'asset_bundle.dart';
|
||||
import 'binary_messenger.dart';
|
||||
@ -27,6 +28,8 @@ mixin ServicesBinding on BindingBase {
|
||||
window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
|
||||
initLicenses();
|
||||
SystemChannels.system.setMessageHandler(handleSystemMessage);
|
||||
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
|
||||
readInitialLifecycleStateFromNativeWindow();
|
||||
}
|
||||
|
||||
/// The current [ServicesBinding], if one has been created.
|
||||
@ -162,6 +165,48 @@ mixin ServicesBinding on BindingBase {
|
||||
void evict(String asset) {
|
||||
rootBundle.evict(asset);
|
||||
}
|
||||
|
||||
// App life cycle
|
||||
|
||||
/// Initializes the [lifecycleState] with the [initialLifecycleState] from the
|
||||
/// window.
|
||||
///
|
||||
/// Once the [lifecycleState] is populated through any means (including this
|
||||
/// method), this method will do nothing. This is because the
|
||||
/// [initialLifecycleState] may already be stale and it no longer makes sense
|
||||
/// to use the initial state at dart vm startup as the current state anymore.
|
||||
///
|
||||
/// The latest state should be obtained by subscribing to
|
||||
/// [WidgetsBindingObserver.didChangeAppLifecycleState].
|
||||
@protected
|
||||
void readInitialLifecycleStateFromNativeWindow() {
|
||||
if (lifecycleState != null) {
|
||||
return;
|
||||
}
|
||||
final AppLifecycleState state = _parseAppLifecycleMessage(window.initialLifecycleState);
|
||||
if (state != null) {
|
||||
handleAppLifecycleStateChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> _handleLifecycleMessage(String message) async {
|
||||
handleAppLifecycleStateChanged(_parseAppLifecycleMessage(message));
|
||||
return null;
|
||||
}
|
||||
|
||||
static AppLifecycleState _parseAppLifecycleMessage(String message) {
|
||||
switch (message) {
|
||||
case 'AppLifecycleState.paused':
|
||||
return AppLifecycleState.paused;
|
||||
case 'AppLifecycleState.resumed':
|
||||
return AppLifecycleState.resumed;
|
||||
case 'AppLifecycleState.inactive':
|
||||
return AppLifecycleState.inactive;
|
||||
case 'AppLifecycleState.detached':
|
||||
return AppLifecycleState.detached;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// The default implementation of [BinaryMessenger].
|
||||
|
@ -1166,7 +1166,7 @@ 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.
|
||||
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
|
||||
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
|
||||
|
@ -16,9 +16,9 @@ import 'package:flutter/widgets.dart';
|
||||
import '../flutter_test_alternative.dart';
|
||||
|
||||
class TestServiceExtensionsBinding extends BindingBase
|
||||
with ServicesBinding,
|
||||
with SchedulerBinding,
|
||||
ServicesBinding,
|
||||
GestureBinding,
|
||||
SchedulerBinding,
|
||||
PaintingBinding,
|
||||
SemanticsBinding,
|
||||
RendererBinding,
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -85,9 +86,15 @@ class TestBindingBase implements BindingBase {
|
||||
|
||||
@override
|
||||
ui.Window get window => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
ui.AppLifecycleState get lifecycleState => null;
|
||||
|
||||
@override
|
||||
void handleAppLifecycleStateChanged(ui.AppLifecycleState state) { }
|
||||
}
|
||||
|
||||
class TestPaintingBinding extends TestBindingBase with ServicesBinding, PaintingBinding {
|
||||
class TestPaintingBinding extends TestBindingBase with SchedulerBinding, ServicesBinding, PaintingBinding {
|
||||
|
||||
@override
|
||||
final FakeImageCache imageCache = FakeImageCache();
|
||||
|
@ -7,9 +7,10 @@ import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class PaintingBindingSpy extends BindingBase with ServicesBinding, PaintingBinding {
|
||||
class PaintingBindingSpy extends BindingBase with SchedulerBinding, ServicesBinding, PaintingBinding {
|
||||
int counter = 0;
|
||||
int get instantiateImageCodecCalledCount => counter;
|
||||
|
||||
|
@ -17,7 +17,7 @@ import '../flutter_test_alternative.dart';
|
||||
typedef HandleEventCallback = void Function(PointerEvent event);
|
||||
|
||||
class _TestGestureFlutterBinding extends BindingBase
|
||||
with ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, RendererBinding {
|
||||
with SchedulerBinding, ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding {
|
||||
@override
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
|
@ -12,7 +12,7 @@ import 'package:flutter_test/flutter_test.dart' show EnginePhase, fail;
|
||||
export 'package:flutter/foundation.dart' show FlutterError, FlutterErrorDetails;
|
||||
export 'package:flutter_test/flutter_test.dart' show EnginePhase;
|
||||
|
||||
class TestRenderingFlutterBinding extends BindingBase with ServicesBinding, GestureBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding {
|
||||
class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding {
|
||||
/// Creates a binding for testing rendering library functionality.
|
||||
///
|
||||
/// If [onErrors] is not null, it is called if [FlutterError] caught any errors
|
||||
|
@ -10,7 +10,7 @@ import '../flutter_test_alternative.dart';
|
||||
|
||||
import 'scheduler_tester.dart';
|
||||
|
||||
class TestSchedulerBinding extends BindingBase with ServicesBinding, SchedulerBinding { }
|
||||
class TestSchedulerBinding extends BindingBase with SchedulerBinding, ServicesBinding { }
|
||||
|
||||
void main() {
|
||||
final SchedulerBinding scheduler = TestSchedulerBinding();
|
||||
|
@ -12,7 +12,7 @@ import 'package:flutter/services.dart';
|
||||
import '../flutter_test_alternative.dart';
|
||||
import 'scheduler_tester.dart';
|
||||
|
||||
class TestSchedulerBinding extends BindingBase with ServicesBinding, SchedulerBinding {
|
||||
class TestSchedulerBinding extends BindingBase with SchedulerBinding, ServicesBinding {
|
||||
final Map<String, List<Map<String, dynamic>>> eventsDispatched = <String, List<Map<String, dynamic>>>{};
|
||||
|
||||
@override
|
||||
|
@ -9,10 +9,11 @@ import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
class TestChannelBuffersFlutterBinding extends BindingBase with ServicesBinding {
|
||||
class TestChannelBuffersFlutterBinding extends BindingBase with SchedulerBinding, ServicesBinding {
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
@ -3,13 +3,13 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('initialLifecycleState is used to init state paused', (WidgetTester tester) async {
|
||||
// The lifecycleState is null initially in tests as there is no
|
||||
// initialLifecycleState.
|
||||
expect(SchedulerBinding.instance.lifecycleState, equals(null));
|
||||
expect(ServicesBinding.instance.lifecycleState, equals(null));
|
||||
// Mock the Window to provide paused as the AppLifecycleState
|
||||
final TestWidgetsFlutterBinding binding = tester.binding;
|
||||
// Use paused as the initial state.
|
||||
@ -18,6 +18,6 @@ void main() {
|
||||
|
||||
// The lifecycleState should now be the state we passed above,
|
||||
// even though no lifecycle event was fired from the platform.
|
||||
expect(SchedulerBinding.instance.lifecycleState.toString(), equals('AppLifecycleState.paused'));
|
||||
expect(ServicesBinding.instance.lifecycleState.toString(), equals('AppLifecycleState.paused'));
|
||||
});
|
||||
}
|
@ -42,7 +42,7 @@ const String _extensionMethod = 'ext.flutter.$_extensionMethodName';
|
||||
/// eventually completes to a string response.
|
||||
typedef DataHandler = Future<String> Function(String message);
|
||||
|
||||
class _DriverBinding extends BindingBase with ServicesBinding, SchedulerBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
|
||||
class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
|
||||
_DriverBinding(this._handler, this._silenceErrors);
|
||||
|
||||
final DataHandler _handler;
|
||||
|
@ -155,8 +155,8 @@ class TestDefaultBinaryMessenger extends BinaryMessenger {
|
||||
/// `HttpClient` to the code making the call, so that it can appropriately mock
|
||||
/// or fake responses.
|
||||
abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
with ServicesBinding,
|
||||
SchedulerBinding,
|
||||
with SchedulerBinding,
|
||||
ServicesBinding,
|
||||
GestureBinding,
|
||||
SemanticsBinding,
|
||||
RendererBinding,
|
||||
|
Loading…
Reference in New Issue
Block a user