Skip to content

Commit

Permalink
feat: Debouncing of SentryWidgetsBindingObserver.didChangeMetrics. #400
Browse files Browse the repository at this point in the history
… (#2232)

* feat: add debouncer for SentryWidgetsBindingObserver.didChangeMetrics

* adapt tests for debouncing

* add changelog entry for debouncer

* Update flutter/lib/src/utils/debouncer.dart

Co-authored-by: Giancarlo Buenaflor <[email protected]>

* Update flutter/test/widgets_binding_observer_test.dart

Co-authored-by: Giancarlo Buenaflor <[email protected]>

* add internal to debouncer and add whitespaces to comments

---------

Co-authored-by: Giancarlo Buenaflor <[email protected]>
  • Loading branch information
martinhaintz and buenaflor authored Aug 19, 2024
1 parent 73d70bf commit 256df44
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
SentryNavigatorObserver(ignoreRoutes: ["/ignoreThisRoute"]),
```

### Improvements

- Debouncing of SentryWidgetsBindingObserver.didChangeMetrics with delay of 100ms. ([#2232](https://github.com/getsentry/sentry-dart/pull/2232))

### Dependencies

- Bump Android SDK from v7.13.0 to v7.14.0 ([#2228](https://github.com/getsentry/sentry-dart/pull/2228))
Expand Down
20 changes: 20 additions & 0 deletions flutter/lib/src/utils/debouncer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:meta/meta.dart';

@internal
class Debouncer {
final int milliseconds;
Timer? _timer;

Debouncer({required this.milliseconds});

void run(VoidCallback action) {
_timer?.cancel();
_timer = Timer(Duration(milliseconds: milliseconds), action);
}

void dispose() {
_timer?.cancel();
}
}
12 changes: 9 additions & 3 deletions flutter/lib/src/widgets_binding_observer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../sentry_flutter.dart';
import 'utils/debouncer.dart';

/// This is a `WidgetsBindingObserver` which can observe some events of a
/// Flutter application.
Expand Down Expand Up @@ -50,6 +51,8 @@ class SentryWidgetsBindingObserver with WidgetsBindingObserver {
// ignore: deprecated_member_use
final StreamController<SingletonFlutterWindow?> _screenSizeStreamController;

final _didChangeMetricsDebouncer = Debouncer(milliseconds: 100);

/// This method records lifecycle events.
/// It tries to mimic the behavior of ActivityBreadcrumbsIntegration of Sentry
/// Android for lifecycle events.
Expand Down Expand Up @@ -88,9 +91,12 @@ class SentryWidgetsBindingObserver with WidgetsBindingObserver {
if (!_options.enableWindowMetricBreadcrumbs) {
return;
}
// ignore: deprecated_member_use
final window = _options.bindingUtils.instance?.window;
_screenSizeStreamController.add(window);

_didChangeMetricsDebouncer.run(() {
// ignore: deprecated_member_use
final window = _options.bindingUtils.instance?.window;
_screenSizeStreamController.add(window);
});
}

void _onScreenSizeChanged(Map<String, dynamic> data) {
Expand Down
77 changes: 77 additions & 0 deletions flutter/test/widgets_binding_observer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ void main() {
// ignore: deprecated_member_use
window.physicalSizeTestValue = Size(newWidth, newHeight);

// waiting for debouncing with 100ms added https://github.com/getsentry/sentry-dart/issues/400
await tester.pump(Duration(milliseconds: 150));

final breadcrumb =
verify(hub.addBreadcrumb(captureAny)).captured.single as Breadcrumb;

Expand Down Expand Up @@ -230,6 +233,9 @@ void main() {
// ignore: deprecated_member_use
window.devicePixelRatioTestValue = newPixelRatio;

// waiting for debouncing with 100ms added https://github.com/getsentry/sentry-dart/issues/400
await tester.pump(Duration(milliseconds: 150));

final breadcrumb =
verify(hub.addBreadcrumb(captureAny)).captured.single as Breadcrumb;

Expand Down Expand Up @@ -265,6 +271,9 @@ void main() {
// ignore: deprecated_member_use
window.viewInsetsTestValue = WindowPadding.zero;

// waiting for debouncing with 100ms added https://github.com/getsentry/sentry-dart/issues/400
await tester.pump(Duration(milliseconds: 150));

verifyNever(hub.addBreadcrumb(captureAny));

instance.removeObserver(observer);
Expand All @@ -286,6 +295,9 @@ void main() {

window.onMetricsChanged!();

// waiting for debouncing with 100ms added https://github.com/getsentry/sentry-dart/issues/400
await tester.pump(Duration(milliseconds: 150));

verifyNever(hub.addBreadcrumb(captureAny));

instance.removeObserver(observer);
Expand Down Expand Up @@ -400,5 +412,70 @@ void main() {

instance.removeObserver(observer);
});

testWidgets('debouncing didChangeMetrics with 100ms delay',
(WidgetTester tester) async {
final hub = MockHub();

final observer = SentryWidgetsBindingObserver(
hub: hub,
options: flutterTrackingEnabledOptions,
);
final instance = tester.binding;
instance.addObserver(observer);

// ignore: deprecated_member_use
final window = instance.window;

// ignore: deprecated_member_use
window.physicalSizeTestValue = window.physicalSize;

const newPixelRatio = 1.7;
// ignore: deprecated_member_use
window.devicePixelRatioTestValue = newPixelRatio;

verifyNever(hub.addBreadcrumb(captureAny));

// waiting for debouncing with 100ms added https://github.com/getsentry/sentry-dart/issues/400
await tester.pump(Duration(milliseconds: 150));

verify(hub.addBreadcrumb(captureAny));

instance.removeObserver(observer);
});

testWidgets('debouncing: didChangeMetrics is called only once in 100ms',
(WidgetTester tester) async {
final hub = MockHub();

final observer = SentryWidgetsBindingObserver(
hub: hub,
options: flutterTrackingEnabledOptions,
);
final instance = tester.binding;
instance.addObserver(observer);

// ignore: deprecated_member_use
final window = instance.window;

// ignore: deprecated_member_use
window.physicalSizeTestValue = window.physicalSize;

// ignore: deprecated_member_use
window.devicePixelRatioTestValue = 2.1;
// ignore: deprecated_member_use
window.devicePixelRatioTestValue = 2.2;
// ignore: deprecated_member_use
window.devicePixelRatioTestValue = 2.3;

verifyNever(hub.addBreadcrumb(captureAny));

// waiting for debouncing with 100ms added https://github.com/getsentry/sentry-dart/issues/400
await tester.pump(Duration(milliseconds: 150));

verify(hub.addBreadcrumb(captureAny)).called(1);

instance.removeObserver(observer);
});
});
}

0 comments on commit 256df44

Please sign in to comment.