1
0
mirror of https://github.com/flutter/samples.git synced 2025-11-08 22:09:06 +00:00

Simplify experimental pedometer example (#2104)

Since ffigen added support for
[`NativeCallable.listener`](https://api.flutter.dev/flutter/dart-ffi/NativeCallable/NativeCallable.listener.html)
to its ObjC bindings, this example can be simplified. We can replace the
`Dart_Port` logic with `ObjCBlock.listener`, which lets us get rid of
most of the native code.

We still need a small bit of native code to `retain` a reference to the
callback's arguments before invoking the listener, otherwise the
arguments may be ref counted and deleted before the Dart side of the
callback is invoked. See https://github.com/dart-lang/native/issues/835
This commit is contained in:
Liam Appelbe
2023-12-06 00:58:58 -08:00
committed by GitHub
parent e598d6a771
commit f0e6da6d24
5 changed files with 27861 additions and 21805 deletions

View File

@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:collection';
import 'dart:ffi' as ffi;
import 'dart:io';
import 'dart:isolate';
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
@@ -73,7 +74,7 @@ class _IOSStepsRepo implements StepsRepo {
// Create a new NSString with the formatted date and timezone.
final nString = pd.NSString(lib, "$formattedDate $tz");
// Convert the NSString to NSDate.
return formatter.dateFromString_(nString);
return formatter.dateFromString_(nString)!;
}
@override
@@ -83,37 +84,35 @@ class _IOSStepsRepo implements StepsRepo {
return [];
}
final futures = <Future>[];
final handlers = [];
final futures = <Future<Steps?>>[];
final now = DateTime.now();
for (var h = 0; h <= now.hour; h++) {
// Open up a port to receive data from native side.
final receivePort = ReceivePort();
final nativePort = receivePort.sendPort.nativePort;
final start = dateConverter(DateTime(now.year, now.month, now.day, h));
final end = dateConverter(DateTime(now.year, now.month, now.day, h + 1));
final completer = Completer<Steps?>();
futures.add(completer.future);
pd.PedometerHelper.startPedometerWithPort_pedometer_start_end_(
helpLib,
nativePort,
client,
start,
end,
);
// Handle the data received from native side.
futures.add(receivePort.first);
final handler = helpLib.wrapCallback(
pd.ObjCBlock_ffiVoid_CMPedometerData_NSError.listener(lib,
(pd.CMPedometerData? result, pd.NSError? error) {
if (result != null) {
final stepCount = result.numberOfSteps.intValue;
final startHour =
hourFormatter.stringFromDate_(result.startDate).toString();
completer.complete(Steps(startHour, stepCount));
} else {
debugPrint("Query error: ${error?.localizedDescription}");
completer.complete(null);
}
}));
handlers.add(handler);
client.queryPedometerDataFromDate_toDate_withHandler_(
start, end, handler);
}
final data = await Future.wait(futures);
return data.where((e) => e != null).cast<int>().map((address) {
final result = ffi.Pointer<pd.ObjCObject>.fromAddress(address);
final pedometerData =
pd.CMPedometerData.castFromPointer(lib, result, release: true);
final stepCount = pedometerData.numberOfSteps?.intValue ?? 0;
final startHour =
hourFormatter.stringFromDate_(pedometerData.startDate!).toString();
return Steps(startHour, stepCount);
}).toList();
return (await Future.wait(futures)).nonNulls.toList();
}
}