Commit a7c3bf48 authored by Devon Carew's avatar Devon Carew Committed by GitHub

perform the initial poll for devices quicker (#11356)

* perform the initial poll for devices quicker

* add a Poller class

* test the new Poller class
parent bbcfb8d5
......@@ -10,6 +10,7 @@ import 'package:crypto/crypto.dart';
import 'package:intl/intl.dart';
import 'package:quiver/time.dart';
import '../globals.dart';
import 'context.dart';
import 'file_system.dart';
import 'platform.dart';
......@@ -216,3 +217,42 @@ class Uuid {
}
Clock get clock => context.putIfAbsent(Clock, () => const Clock());
typedef Future<Null> AsyncCallback();
/// A [Timer] inspired class that:
/// - has a different initial value for the first callback delay
/// - waits for a callback to be complete before it starts the next timer
class Poller {
Poller(this.callback, this.pollingInterval, { this.initialDelay: Duration.ZERO }) {
new Future<Null>.delayed(initialDelay, _handleCallback);
}
final AsyncCallback callback;
final Duration initialDelay;
final Duration pollingInterval;
bool _cancelled = false;
Timer _timer;
Future<Null> _handleCallback() async {
if (_cancelled)
return;
try {
await callback();
} catch (error) {
printTrace('Error from poller: $error');
}
if (!_cancelled)
_timer = new Timer(pollingInterval, _handleCallback);
}
/// Cancels the poller.
void cancel() {
_cancelled = true;
_timer?.cancel();
_timer = null;
}
}
......@@ -116,35 +116,28 @@ abstract class PollingDeviceDiscovery extends DeviceDiscovery {
final String name;
ItemListNotifier<Device> _items;
Timer _timer;
Poller _poller;
Future<List<Device>> pollingGetDevices();
void startPolling() {
if (_timer == null) {
if (_poller == null) {
_items ??= new ItemListNotifier<Device>();
bool _fetchingDevices = false;
_timer = new Timer.periodic(_pollingInterval, (Timer timer) async {
if (_fetchingDevices) {
printTrace('Skipping device poll: already in progress');
return;
}
_fetchingDevices = true;
_poller = new Poller(() async {
try {
final List<Device> devices = await pollingGetDevices().timeout(_pollingTimeout);
_items.updateWithNewList(devices);
} on TimeoutException {
printTrace('Device poll timed out.');
} finally {
_fetchingDevices = false;
}
});
}, _pollingInterval);
}
}
void stopPolling() {
_timer?.cancel();
_timer = null;
_poller?.cancel();
_poller = null;
}
@override
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter_tools/src/base/utils.dart';
import 'package:flutter_tools/src/base/version.dart';
import 'package:test/test.dart';
......@@ -115,4 +117,52 @@ baz=qux
expect(new Version.parse('Preview2.2'), isNull);
});
});
group('Poller', () {
const Duration kShortDelay = const Duration(milliseconds: 100);
Poller poller;
tearDown(() {
poller?.cancel();
});
test('fires at start', () async {
bool called = false;
poller = new Poller(() {
called = true;
}, const Duration(seconds: 1));
expect(called, false);
await new Future<Null>.delayed(kShortDelay);
expect(called, true);
});
test('runs periodically', () async {
// Ensure we get the first (no-delay) callback, and one of the periodic callbacks.
int callCount = 0;
poller = new Poller(() {
callCount++;
}, new Duration(milliseconds: kShortDelay.inMilliseconds ~/ 2));
expect(callCount, 0);
await new Future<Null>.delayed(kShortDelay);
expect(callCount, greaterThanOrEqualTo(2));
});
test('no quicker then the periodic delay', () async {
// Make sure that the poller polls at delay + the time it took to run the callback.
final Completer<Duration> completer = new Completer<Duration>();
DateTime firstTime;
poller = new Poller(() async {
if (firstTime == null)
firstTime = new DateTime.now();
else
completer.complete(new DateTime.now().difference(firstTime));
// introduce a delay
await new Future<Null>.delayed(kShortDelay);
}, kShortDelay);
final Duration duration = await completer.future;
expect(duration, greaterThanOrEqualTo(new Duration(milliseconds: kShortDelay.inMilliseconds * 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