Skip to content

Fix black viewfinder after resuming from background - #135

Merged
iakdis merged 1 commit into
iakdis:masterfrom
AlexanderWalls:fix/black-viewfinder-on-resume
Sep 25, 2026
Merged

iakdis merged 1 commit into
iakdis:masterfrom
AlexanderWalls:fix/black-viewfinder-on-resume

Conversation

@AlexanderWalls

Copy link
Copy Markdown
Contributor

Summary

Fixes the camera preview going permanently black after any resume from the background — including brief interruptions like pulling down the notification shade, not just switching apps.

Root cause: camera teardown was triggered on AppLifecycleState.inactive, which fires for transient interruptions (shade pull, system dialogs) as well as real backgrounding. The resulting dispose()/initialize() calls were unawaited and unserialized, so overlapping lifecycle events could race the native camera controller — the plugin would report itself initialized (so photo capture kept working) while the preview surface never got reattached, leaving it black until the app was fully killed and relaunched.

Changes

  • Only tear the camera down on paused/hidden; inactive is now a no-op.
  • Serialize hide/show through a single queued future so dispose() and initialize() can never overlap.
  • Rebuild the preview from the live controller inside the ValueListenableBuilder instead of a stale reference captured outside it, and key CameraPreview on the controller's camera id so a new controller gets a fresh texture subtree.
  • Recover safely if the controller is missing/uninitialized when switching cameras or toggling video mode, instead of calling into a dead controller.

Fixes #127.

Test plan

  • flutter analyze clean
  • Verified on a physical device (Android 16): notification shade pulls, home/reopen from recents, lock/unlock, opening Settings and returning, rapid repeated shade pulls, photo capture after each return, front/rear camera switch after return, and starting a video recording then backgrounding/returning — preview stayed live in all cases, no black screen reproduced.

Camera lifecycle handling tore the camera down on AppLifecycleState.inactive,
which fires for transient interruptions like the notification shade or a
system dialog, not just real backgrounding. Because dispose()/initialize()
calls were unawaited and unserialized, inactive/resumed events firing in
quick succession could overlap them, leaving the native preview surface
detached from the repeating capture request while the controller still
reported itself initialized (so photo capture kept working, but the preview
stayed black until the app was fully killed and relaunched).

- Only tear the camera down on paused/hidden; inactive is now a no-op.
- Serialize hide/show through a single queued future so dispose() and
  initialize() can never overlap.
- Rebuild the preview from the live controller inside the
  ValueListenableBuilder instead of a stale reference captured outside it,
  and key CameraPreview on the controller's camera id so a new controller
  gets a fresh texture subtree.
- Recover safely if the controller is missing/uninitialized when switching
  cameras or toggling video mode instead of calling into a dead controller.
@AlexanderWalls

Copy link
Copy Markdown
Contributor Author

Morning - any chance of getting this reviewer and merged? 😇

@iakdis

iakdis commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Hi @AlexanderWalls, thank you for the PR! I just tested it myself and it looks good on my side. I'll also merge your other PR. Thanks again for the contributions!

@iakdis
iakdis merged commit d8db089 into iakdis:master Sep 25, 2026
@AlexanderWalls

Copy link
Copy Markdown
Contributor Author

Hi @AlexanderWalls, thank you for the PR! I just tested it myself and it looks good on my side. I'll also merge your other PR. Thanks again for the contributions!

You're totally welcome! I'm also experiencing a no sound issue when recording video, so will investigate that separately

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.

[Bug] preview screen blacks out after being idle

2 participants