Skip to content

Conversation

@liyuqian
Copy link
Contributor

This fixes #39277

The following tests cover this change:

  • packages/flutter/test/foundation/service_extensions_test.dart
  • packages/flutter/test/scheduler/scheduler_test.dart

// TODO(liyuqian): once this is merged, modify the doc of
// [Window.onReportTimings] inside the engine repo to recommend using this
// API instead of using [Window.onReportTimings] directly.
_timingsCallbacksEnabled[callback] = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I add the same callback twice it will only get called once? That's probably expected, but might be worth documenting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've modified it to use a list so now it actually gets called twice. Documented such behavior too.

assert(window.onReportTimings == null);
window.onReportTimings = (List<FrameTiming> timings) {
for (TimingsCallback callback in _timingsCallbacks) {
callback(timings);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if callback removes itself from _timingsCallbacks? You probably want to iterate over a copy of _timingsCallbacks to avoid problems (_timingsCallbacks.toList() should work).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original map was for that. But I've changed it the the cloned list approach as you suggested. I was trying to save some copying time but I guess the saving isn't worth the confusion.

/// Removes a callback that was earlier added by [addTimingsCallback].
void removeTimingsCallback(TimingsCallback callback) {
assert(_timingsCallbacksEnabled.containsKey(callback));
_timingsCallbacksEnabled[callback] = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you keep track of whats enabled/disabled? Why not just remove it?

It also looks like this Map never gets cleaned up and the callback (and all the resources closured in to it) will be held in memory indefinitely. That seems like a leak?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to list and removed the calllback when needed.


void _executeTimingsCallbacks(List<FrameTiming> timings) {
final List<TimingsCallback> clonedCallbacks =
List<TimingsCallback>.from(_timingsCallbacks);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: either indent further or move to previous line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this! I thought I indented by somehow it's missing...

final List<TimingsCallback> clonedCallbacks =
List<TimingsCallback>.from(_timingsCallbacks);
for (TimingsCallback callback in clonedCallbacks) {
callback(timings);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other places where we have similar code we check here if the callback is still in clonedCallbacks, for example:

if (_listeners.contains(listener))
listener();

That way if your list is [callbackA, callbackB] and callbackA removes callbackB, callbackB is not called again. This would probably also make sense here?

Also from that link: Should we catch exceptions here that happen while executing callback?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Also added a test for the error handling.

}
}

final List<TimingsCallback> _timingsCallbacks = <TimingsCallback>[];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would move this field up above addTimingsCallback, but that's probably up to personal taste.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@goderbauer goderbauer added the framework flutter/packages/flutter repository. See also f: labels. label Oct 29, 2019
@Piinks Piinks added the c: performance Relates to speed or footprint issues (see "perf:" labels) label Oct 29, 2019
Copy link
Member

@goderbauer goderbauer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@liyuqian liyuqian merged commit 40670c0 into flutter:master Oct 31, 2019
@liyuqian liyuqian deleted the scheduler_binding branch October 31, 2019 04:54
Inconnu08 pushed a commit to Inconnu08/flutter that referenced this pull request Nov 26, 2019
This fixes flutter#39277

The following tests cover this change:
- packages/flutter/test/foundation/service_extensions_test.dart
- packages/flutter/test/scheduler/scheduler_test.dart
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 3, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

c: performance Relates to speed or footprint issues (see "perf:" labels) framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose FrameTiming with multiple listeners instead of a simple callback

4 participants