Skip to content

fix lifecycle cleanup issues#222

Merged
DennisMoschina merged 3 commits intoui-redesignfrom
ui-redesign-fixes
Mar 9, 2026
Merged

fix lifecycle cleanup issues#222
DennisMoschina merged 3 commits intoui-redesignfrom
ui-redesign-fixes

Conversation

@o-bagge
Copy link
Collaborator

@o-bagge o-bagge commented Mar 6, 2026

Prevents resource leaks during reconnect/disconnect cycles and long app sessions.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

Visit the preview URL for this PR (updated for commit b355310):

https://open-earable-web--pr222-ui-redesign-fixes-osyvhx8y.web.app

(expires Mon, 06 Apr 2026 10:55:28 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: c7397c11177c71d8d81172cea9365829823fb41c

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Improves lifecycle cleanup for wearable-related providers to reduce resource leaks during reconnect/disconnect cycles and long-running app sessions.

Changes:

  • Add explicit disposal logic to WearablesProvider, including canceling subscriptions, disposing child providers, and closing event stream controllers.
  • Add disposal logic to SensorRecorderProvider to stop recorders and clear internal state on teardown.
  • Update SensorStreams.shared to evict cached broadcast streams when the stream is canceled.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
open_wearable/lib/view_models/wearables_provider.dart Adds disposed-guarding and a full dispose() implementation; routes event emission through helper methods.
open_wearable/lib/view_models/sensor_recorder_provider.dart Adds dispose() to stop per-wearable recorders and clear recorder state.
open_wearable/lib/models/sensor_streams.dart Removes cached shared stream entries when the broadcast stream is canceled.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

),
);
}
if (_disposed) {
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

The _disposed guard in _handleCapabilitiesChanged is currently after side effects (e.g., initializing sensor configs / scheduling work). If a capability event arrives during teardown or after removeWearable, this handler can recreate per-wearable state even though the provider is disposed/removed. Add the guard at the start of the method (and consider also checking the wearable is still tracked, e.g., present in _capabilitySubscriptions/_wearables) before doing any work.

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +21
return sensor.sensorStream.asBroadcastStream(
onCancel: (_) {
_sharedStreams.remove(sensor);
},
);
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

SensorStreams.shared only evicts the cached entry via onCancel. If the underlying sensor.sensorStream completes (e.g., because a device disconnects) without listeners explicitly canceling first, onCancel won’t run and _sharedStreams can retain a closed stream, causing future callers to receive an already-terminated stream. Consider wrapping the source stream so you also remove the cache entry on onDone/onError (or otherwise ensure clearForSensor is invoked on disconnect).

Copilot uses AI. Check for mistakes.
Comment on lines 15 to +22
static Stream<SensorValue> shared(Sensor sensor) {
return _sharedStreams.putIfAbsent(
sensor,
() => sensor.sensorStream.asBroadcastStream(),
);
return _sharedStreams.putIfAbsent(sensor, () {
return sensor.sensorStream.asBroadcastStream(
onCancel: (_) {
_sharedStreams.remove(sensor);
},
);
});
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

This change modifies the lifecycle semantics of the shared-stream cache (eviction on cancel). There doesn’t appear to be a unit test covering SensorStreams.shared cache insertion/eviction behavior, which makes regressions in long-session/reconnect scenarios hard to catch. Consider adding a small test that verifies the same stream instance is reused while active and that the cache entry is removed after the last listener cancels.

Copilot uses AI. Check for mistakes.
@DennisMoschina DennisMoschina merged commit 93d41d3 into ui-redesign Mar 9, 2026
8 checks passed
@DennisMoschina DennisMoschina deleted the ui-redesign-fixes branch March 9, 2026 12:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants