Unverified Commit 78e044f5 authored by amirh's avatar amirh Committed by GitHub

Cancel the animated image stream timer if all listeners were removed. (#13158)

This is a bug in my previous CL: instead of cancelling the timer if
there are no more listeners, I canceled it if there were listeners (I
can claim I just missed a not :) ).

Not cancelling the timer when removing the last listener was not that bad, as
the timer callback is guarded by a check to see if there are listeners.
So the animation will not continue.

But in the case there were multiple listeners on the same stream, and
one of them is removed, this bug will stop the animation for all other
listeners.
I added a test case for this scenario.
parent 2db0c25f
......@@ -440,7 +440,7 @@ class MultiFrameImageStreamCompleter extends ImageStreamCompleter {
@override
void removeListener(ImageListener listener) {
super.removeListener(listener);
if (_hasActiveListeners) {
if (!_hasActiveListeners) {
_timer?.cancel();
_timer = null;
}
......
......@@ -312,6 +312,86 @@ void main() {
expect(mockCodec.numFramesAsked, 3);
});
testWidgets('multiple stream listeners', (WidgetTester tester) async {
final MockCodec mockCodec = new MockCodec();
mockCodec.frameCount = 2;
mockCodec.repetitionCount = -1;
final Completer<Codec> codecCompleter = new Completer<Codec>();
final ImageStreamCompleter imageStream = new MultiFrameImageStreamCompleter(
codec: codecCompleter.future,
scale: 1.0,
);
final List<ImageInfo> emittedImages1 = <ImageInfo>[];
final ImageListener listener1 = (ImageInfo image, bool synchronousCall) {
emittedImages1.add(image);
};
final List<ImageInfo> emittedImages2 = <ImageInfo>[];
final ImageListener listener2 = (ImageInfo image, bool synchronousCall) {
emittedImages2.add(image);
};
imageStream.addListener(listener1);
imageStream.addListener(listener2);
codecCompleter.complete(mockCodec);
await tester.idle();
final FrameInfo frame1 = new FakeFrameInfo(20, 10, const Duration(milliseconds: 200));
final FrameInfo frame2 = new FakeFrameInfo(200, 100, const Duration(milliseconds: 400));
mockCodec.completeNextFrame(frame1);
await tester.idle(); // let nextFrameFuture complete
await tester.pump(); // first animation frame shows on first app frame.
expect(emittedImages1, equals(<ImageInfo>[new ImageInfo(image: frame1.image)]));
expect(emittedImages2, equals(<ImageInfo>[new ImageInfo(image: frame1.image)]));
mockCodec.completeNextFrame(frame2);
await tester.idle(); // let nextFrameFuture complete
await tester.pump(); // next app frame will schedule a timer.
imageStream.removeListener(listener1);
await tester.pump(const Duration(milliseconds: 400)); // emit 2nd frame.
expect(emittedImages1, equals(<ImageInfo>[new ImageInfo(image: frame1.image)]));
expect(emittedImages2, equals(<ImageInfo>[
new ImageInfo(image: frame1.image),
new ImageInfo(image: frame2.image),
]));
});
testWidgets('timer is canceled when listeners are removed', (WidgetTester tester) async {
final MockCodec mockCodec = new MockCodec();
mockCodec.frameCount = 2;
mockCodec.repetitionCount = -1;
final Completer<Codec> codecCompleter = new Completer<Codec>();
final ImageStreamCompleter imageStream = new MultiFrameImageStreamCompleter(
codec: codecCompleter.future,
scale: 1.0,
);
final ImageListener listener = (ImageInfo image, bool synchronousCall) {};
imageStream.addListener(listener);
codecCompleter.complete(mockCodec);
await tester.idle();
final FrameInfo frame1 = new FakeFrameInfo(20, 10, const Duration(milliseconds: 200));
final FrameInfo frame2 = new FakeFrameInfo(200, 100, const Duration(milliseconds: 400));
mockCodec.completeNextFrame(frame1);
await tester.idle(); // let nextFrameFuture complete
await tester.pump(); // first animation frame shows on first app frame.
mockCodec.completeNextFrame(frame2);
await tester.idle(); // let nextFrameFuture complete
await tester.pump();
imageStream.removeListener(listener);
// The test framework will fail this if there are pending timers at this
// point.
});
testWidgets('timeDilation affects animation frame timers', (WidgetTester tester) async {
final MockCodec mockCodec = new MockCodec();
mockCodec.frameCount = 2;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment