Commit 83c5279fb26fd355a3130b94b434174365cf243c

Authored by 权海
1 parent a3a0c7ad

feat(ui):startCaculate 增加返回值,原生根据返回值决定是否启用hardness engine,防止后台isolate无法执行

@@ -18,14 +18,26 @@ abstract final class NativeHealthDataUpdateBridge { @@ -18,14 +18,26 @@ abstract final class NativeHealthDataUpdateBridge {
18 18
19 static Future<Object?> _handleMethodCall(MethodCall call) async { 19 static Future<Object?> _handleMethodCall(MethodCall call) async {
20 if (call.method == 'healthDataEngineReady') return true; 20 if (call.method == 'healthDataEngineReady') return true;
21 - if (call.method != 'healthDataUpdated') return null; 21 + if (call.method != 'healthDataUpdated' &&
  22 + call.method != 'calculateHealthDataUpdate') {
  23 + return null;
  24 + }
22 25
23 final dataTypes = _dataTypes(call.arguments); 26 final dataTypes = _dataTypes(call.arguments);
24 debugPrint('[NativeHealthDataUpdateBridge] calculate dataTypes=$dataTypes'); 27 debugPrint('[NativeHealthDataUpdateBridge] calculate dataTypes=$dataTypes');
25 - await Get.find<HealthRawDataCoreService>().onHealthDataUpdated(  
26 - dataTypes: dataTypes,  
27 - );  
28 - return true; 28 + try {
  29 + final hasNewResult =
  30 + await Get.find<HealthRawDataCoreService>().onHealthDataUpdated(
  31 + dataTypes: dataTypes,
  32 + );
  33 + return call.method == 'calculateHealthDataUpdate' ? hasNewResult : true;
  34 + } catch (error, stackTrace) {
  35 + debugPrint(
  36 + '[NativeHealthDataUpdateBridge] calculate.failed '
  37 + 'error=$error stack=$stackTrace',
  38 + );
  39 + return false;
  40 + }
29 } 41 }
30 42
31 static List<int> _dataTypes(Object? arguments) { 43 static List<int> _dataTypes(Object? arguments) {
@@ -71,7 +71,7 @@ class HealthRawDataCoreService { @@ -71,7 +71,7 @@ class HealthRawDataCoreService {
71 Stream<HealthRawDataUpdatedEvent> get healthDataUpdatedStream => 71 Stream<HealthRawDataUpdatedEvent> get healthDataUpdatedStream =>
72 _currentService.healthDataUpdatedStream; 72 _currentService.healthDataUpdatedStream;
73 73
74 - Future<void> onHealthDataUpdated({List<int>? dataTypes}) { 74 + Future<bool> onHealthDataUpdated({List<int>? dataTypes}) {
75 return _currentService.onHealthDataUpdated(dataTypes: dataTypes); 75 return _currentService.onHealthDataUpdated(dataTypes: dataTypes);
76 } 76 }
77 77
@@ -60,7 +60,7 @@ class AppleHealthRawDataCoreService { @@ -60,7 +60,7 @@ class AppleHealthRawDataCoreService {
60 final StreamController<HealthRawDataUpdatedEvent> 60 final StreamController<HealthRawDataUpdatedEvent>
61 _healthDataUpdatedController = 61 _healthDataUpdatedController =
62 StreamController<HealthRawDataUpdatedEvent>.broadcast(); 62 StreamController<HealthRawDataUpdatedEvent>.broadcast();
63 - Future<void>? _healthDataUpdatedCalculation; 63 + Future<bool>? _healthDataUpdatedCalculation;
64 Future<HealthRawStressCalculationResult>? _coreCalculation; 64 Future<HealthRawStressCalculationResult>? _coreCalculation;
65 List<int> _pendingHealthDataUpdatedTypes = const <int>[]; 65 List<int> _pendingHealthDataUpdatedTypes = const <int>[];
66 bool _isUploadingHrvResults = false; 66 bool _isUploadingHrvResults = false;
@@ -107,14 +107,14 @@ class AppleHealthRawDataCoreService { @@ -107,14 +107,14 @@ class AppleHealthRawDataCoreService {
107 Stream<HealthRawDataUpdatedEvent> get healthDataUpdatedStream => 107 Stream<HealthRawDataUpdatedEvent> get healthDataUpdatedStream =>
108 _healthDataUpdatedController.stream; 108 _healthDataUpdatedController.stream;
109 109
110 - Future<void> onHealthDataUpdated({List<int>? dataTypes}) async { 110 + Future<bool> onHealthDataUpdated({List<int>? dataTypes}) async {
111 await _saveNativeCallFlutterChange(dataTypes); 111 await _saveNativeCallFlutterChange(dataTypes);
112 if (_healthDataUpdatedCalculation != null) { 112 if (_healthDataUpdatedCalculation != null) {
113 _pendingHealthDataUpdatedTypes = _mergeHealthDataTypes( 113 _pendingHealthDataUpdatedTypes = _mergeHealthDataTypes(
114 _pendingHealthDataUpdatedTypes, 114 _pendingHealthDataUpdatedTypes,
115 dataTypes, 115 dataTypes,
116 ); 116 );
117 - return _healthDataUpdatedCalculation; 117 + return _healthDataUpdatedCalculation!;
118 } 118 }
119 119
120 _pendingHealthDataUpdatedTypes = _mergeHealthDataTypes( 120 _pendingHealthDataUpdatedTypes = _mergeHealthDataTypes(
@@ -124,7 +124,7 @@ class AppleHealthRawDataCoreService { @@ -124,7 +124,7 @@ class AppleHealthRawDataCoreService {
124 final task = _calculateAndNotifyHealthDataUpdated(); 124 final task = _calculateAndNotifyHealthDataUpdated();
125 _healthDataUpdatedCalculation = task; 125 _healthDataUpdatedCalculation = task;
126 try { 126 try {
127 - await task; 127 + return await task;
128 } finally { 128 } finally {
129 if (identical(_healthDataUpdatedCalculation, task)) { 129 if (identical(_healthDataUpdatedCalculation, task)) {
130 _healthDataUpdatedCalculation = null; 130 _healthDataUpdatedCalculation = null;
@@ -132,14 +132,18 @@ class AppleHealthRawDataCoreService { @@ -132,14 +132,18 @@ class AppleHealthRawDataCoreService {
132 } 132 }
133 } 133 }
134 134
135 - Future<void> _calculateAndNotifyHealthDataUpdated() async { 135 + Future<bool> _calculateAndNotifyHealthDataUpdated() async {
136 try { 136 try {
137 - await startCoreCaculate(); 137 + final result = await startCoreCaculate();
138 final completedDataTypes = _pendingHealthDataUpdatedTypes; 138 final completedDataTypes = _pendingHealthDataUpdatedTypes;
139 await _saveFlutterCaculateFinished(completedDataTypes); 139 await _saveFlutterCaculateFinished(completedDataTypes);
140 _healthDataUpdatedController.add( 140 _healthDataUpdatedController.add(
141 HealthRawDataUpdatedEvent(dataTypes: completedDataTypes), 141 HealthRawDataUpdatedEvent(dataTypes: completedDataTypes),
142 ); 142 );
  143 + return result.hrvStressPoints.isNotEmpty ||
  144 + result.realtimeStressPoints.isNotEmpty ||
  145 + result.dailyStressPoints.isNotEmpty ||
  146 + result.sleepResults.isNotEmpty;
143 } finally { 147 } finally {
144 _pendingHealthDataUpdatedTypes = const <int>[]; 148 _pendingHealthDataUpdatedTypes = const <int>[];
145 } 149 }
@@ -82,11 +82,15 @@ class OHOSHealthRawDataCoreService { @@ -82,11 +82,15 @@ class OHOSHealthRawDataCoreService {
82 Stream<HealthRawDataUpdatedEvent> get healthDataUpdatedStream => 82 Stream<HealthRawDataUpdatedEvent> get healthDataUpdatedStream =>
83 _healthDataUpdatedController.stream; 83 _healthDataUpdatedController.stream;
84 84
85 - Future<void> onHealthDataUpdated({List<int>? dataTypes}) async {  
86 - await startCoreCaculate(); 85 + Future<bool> onHealthDataUpdated({List<int>? dataTypes}) async {
  86 + final result = await startCoreCaculate();
87 _healthDataUpdatedController.add( 87 _healthDataUpdatedController.add(
88 HealthRawDataUpdatedEvent(dataTypes: dataTypes ?? const <int>[]), 88 HealthRawDataUpdatedEvent(dataTypes: dataTypes ?? const <int>[]),
89 ); 89 );
  90 + return result.hrvStressPoints.isNotEmpty ||
  91 + result.realtimeStressPoints.isNotEmpty ||
  92 + result.dailyStressPoints.isNotEmpty ||
  93 + result.sleepResults.isNotEmpty;
90 } 94 }
91 95
92 Future<String> databaseFilePath() { 96 Future<String> databaseFilePath() {
@@ -9,6 +9,7 @@ import 'package:intl/date_symbol_data_local.dart'; @@ -9,6 +9,7 @@ import 'package:intl/date_symbol_data_local.dart';
9 import 'app/bootstrap/app_bootstrap.dart'; 9 import 'app/bootstrap/app_bootstrap.dart';
10 import 'app/double_feel_app.dart'; 10 import 'app/double_feel_app.dart';
11 import 'core/services/raw_data_service/health_raw_data_core_service.dart'; 11 import 'core/services/raw_data_service/health_raw_data_core_service.dart';
  12 +import 'core/services/raw_data_service/health_raw_models.dart';
12 import 'core/theme/app_theme.dart'; 13 import 'core/theme/app_theme.dart';
13 import 'data/local/user_preferences_storage.dart'; 14 import 'data/local/user_preferences_storage.dart';
14 15
@@ -105,12 +106,18 @@ Future<void> _runPendingHealthTasks( @@ -105,12 +106,18 @@ Future<void> _runPendingHealthTasks(
105 106
106 try { 107 try {
107 await _healthBackgroundLog(channel, 'calculate.start'); 108 await _healthBackgroundLog(channel, 'calculate.start');
108 - await Get.find<HealthRawDataCoreService>().startCoreCaculate();  
109 - await _healthBackgroundLog(channel, 'calculate.success'); 109 + final calculation =
  110 + await Get.find<HealthRawDataCoreService>().startCoreCaculate();
  111 + final hasNewResult = _hasNewHealthCalculationResult(calculation);
  112 + await _healthBackgroundLog(
  113 + channel,
  114 + 'calculate.success hasNewResult=$hasNewResult',
  115 + );
110 for (final task in tasks) { 116 for (final task in tasks) {
111 await channel.invokeMethod('healthBackgroundTaskFinished', { 117 await channel.invokeMethod('healthBackgroundTaskFinished', {
112 'taskId': task.taskId, 118 'taskId': task.taskId,
113 'success': true, 119 'success': true,
  120 + 'calculated': hasNewResult,
114 }); 121 });
115 } 122 }
116 } catch (error) { 123 } catch (error) {
@@ -126,6 +133,13 @@ Future<void> _runPendingHealthTasks( @@ -126,6 +133,13 @@ Future<void> _runPendingHealthTasks(
126 } 133 }
127 } 134 }
128 135
  136 +bool _hasNewHealthCalculationResult(HealthRawStressCalculationResult result) {
  137 + return result.hrvStressPoints.isNotEmpty ||
  138 + result.realtimeStressPoints.isNotEmpty ||
  139 + result.dailyStressPoints.isNotEmpty ||
  140 + result.sleepResults.isNotEmpty;
  141 +}
  142 +
129 Future<void> _healthBackgroundLog(MethodChannel channel, String message) async { 143 Future<void> _healthBackgroundLog(MethodChannel channel, String message) async {
130 try { 144 try {
131 await channel.invokeMethod('healthBackgroundLog', { 145 await channel.invokeMethod('healthBackgroundLog', {
@@ -567,13 +567,14 @@ void main() { @@ -567,13 +567,14 @@ void main() {
567 ); 567 );
568 final eventFuture = service.healthDataUpdatedStream.first; 568 final eventFuture = service.healthDataUpdatedStream.first;
569 569
570 - await service.onHealthDataUpdated( 570 + final hasNewResult = await service.onHealthDataUpdated(
571 dataTypes: [ 571 dataTypes: [
572 HealthDataUploadType.hrv.type, 572 HealthDataUploadType.hrv.type,
573 HealthDataUploadType.heartRate.type, 573 HealthDataUploadType.heartRate.type,
574 ], 574 ],
575 ); 575 );
576 576
  577 + expect(hasNewResult, isTrue);
577 final event = await eventFuture; 578 final event = await eventFuture;
578 expect( 579 expect(
579 event.dataTypes, 580 event.dataTypes,
@@ -581,6 +582,24 @@ void main() { @@ -581,6 +582,24 @@ void main() {
581 ); 582 );
582 }); 583 });
583 584
  585 + test('onHealthDataUpdated returns false after an empty calculation',
  586 + () async {
  587 + final api = _FakeHealthKitRawDataHostApi();
  588 + final service = AppleHealthRawDataCoreService(
  589 + healthApi: _FakeHealthKitHostApi(status: 0),
  590 + rawDataApi: api,
  591 + localStore: _MemoryHealthRawStressLocalStore(),
  592 + userIdProvider: () => 42,
  593 + uploadResultsAfterCalculation: false,
  594 + );
  595 +
  596 + final hasNewResult = await service.onHealthDataUpdated(
  597 + dataTypes: [HealthDataUploadType.hrv.type],
  598 + );
  599 +
  600 + expect(hasNewResult, isFalse);
  601 + });
  602 +
584 test('startCoreCaculate calculates and stores sleep results', () async { 603 test('startCoreCaculate calculates and stores sleep results', () async {
585 final now = DateTime.now(); 604 final now = DateTime.now();
586 final day = DateTime(now.year, now.month, now.day); 605 final day = DateTime(now.year, now.month, now.day);