Skip to content

fix: dispose auth subscription and TextEditingControllers (closes #173, #174)#175

Merged
X-Wei merged 1 commit into
X-Wei:masterfrom
EstebanCastel:fix/issue-173-174-stream-and-controller-leaks
May 24, 2026
Merged

fix: dispose auth subscription and TextEditingControllers (closes #173, #174)#175
X-Wei merged 1 commit into
X-Wei:masterfrom
EstebanCastel:fix/issue-173-174-stream-and-controller-leaks

Conversation

@EstebanCastel
Copy link
Copy Markdown
Contributor

Context

This PR is part of an academic analysis of Flutter Catalog conducted for a
mobile development course (ISIS3510, Universidad de los Andes). The focus is
correctness rather than new features. Both changes are confined to the two
files that the linked issues describe; no demo behavior or educational
content is altered beyond what the issues already discussed.

Summary

Closes #173 and #174. Two independent memory-leak fixes:

1. lib/routes/firebase_login_ex.dart (#173)

_auth.authStateChanges().listen(...) previously returned a StreamSubscription
that was discarded, and the listener mutated this._user without setState,
so:

  • the subscription leaked every time the route was opened, and
  • the UI never reflected auth state changes pushed through the stream
    (sign-out from another tab, token expiration, etc.).

The fix:

  • Stores the subscription in a _authSub field.
  • Overrides dispose() to cancel it.
  • Calls setState from the listener so the displayed status text reacts to
    external auth state changes.
  • Adds a mounted guard before setState so callbacks that race with
    navigation do not touch a disposed widget.

2. lib/routes/networking_rest_api_send_ex.dart (#174)

Three TextEditingController instances were created in initState() but
the widget never overrode dispose(). TextEditingController is a
ChangeNotifier retained by every TextField that listens to it. The fix
overrides dispose() and releases the three controllers.

Test plan

  • git diff reviewed — only the two files are touched, additions only
    (no behavior removed from the demos).
  • flutter analyze lib/routes/firebase_login_ex.dart lib/routes/networking_rest_api_send_ex.dart
    — could not run locally because the project requires Flutter SDK >=3.11
    and the local environment is on 3.10. The diff is small and uses only
    standard StatefulWidget patterns (no Dart 3.11 syntax).
  • Manual run of the Firebase Login demo on a physical device to confirm
    that the status text now updates immediately when auth state changes
    through the stream.
  • DevTools Memory snapshot to confirm _FirebaseLoginExampleState and
    _RestApiSendExampleState instances are GC'd after navigating away from
    each demo.

Made with Cursor

…etworking_rest_api_send_ex

Resolves two memory leaks reported in issues X-Wei#173 and X-Wei#174.

firebase_login_ex.dart (X-Wei#173):
- Store the StreamSubscription returned by _auth.authStateChanges().listen
  in a `_authSub` field so it can be cancelled.
- Override dispose() to cancel the subscription.
- Add the missing setState() so the statusText reactsto external auth
  state changes (token expiration, sign-out from another tab, etc.).
- Add a mounted guard before setState() so callbacks that race with
  navigation do not call setState on a disposed widget.

networking_rest_api_send_ex.dart (X-Wei#174):
- Override dispose() to release the three TextEditingController instances
  (_titleController, _contentController, _userIdController) owned by the
  widget. Without this they were retained for the lifetime of the
  process every time the user visited this route.

No behavior change for the demos beyond the auth listener now actually
updating the UI when the auth state changes through the stream.
@X-Wei X-Wei merged commit 91df90c into X-Wei:master May 24, 2026
1 check failed
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.

Auth state subscription is never cancelled and listener does not setState in firebase_login_ex.dart

2 participants