8000 android: keep the app running when its activity is recreated by benface · Pull Request #689 · not-fl3/miniquad · GitHub
[go: up one dir, main page]

Skip to content

android: keep the app running when its activity is recreated - #689

Open
benface wants to merge 1 commit into
not-fl3:masterfrom
benface:android-activity-recreation
Open

benface wants to merge 1 commit into
not-fl3:masterfrom
benface:android-activity-recreation

Conversation

@benface
@benface benface commented Oct 10, 2026 •
Copy link
Copy Markdown
Contributor

Why

Android destroys an activity and creates a new one in the same process after a configuration change the activity doesn't handle itself, such as a new font size or language, and with the "Don't keep activities" developer option. activityOnDestroy quit the app, and the next activityOnCreate called quad_main again, starting a second app in a process that still held the first one's globals. A macroquad app aborts there: in the new render thread, Scudo reports invalid chunk state when deallocating while dropping an Arc<macroquad::material::GlPipelineGuarded> the first app made under its own GL context.

Change

  • Destroy quits only when the activity is finishing (isFinishing()). When Android is about to recreate it, the app keeps running, as it does in the background.
  • activityOnCreate hands a new activity to the running app instead of starting another. The render thread swaps its global reference into ACTIVITY and deletes the old one, so setFullScreen, showKeyboard, the clipboard and load_asset reach the activity on screen. Its surface arrives through the usual surfaceCreated, as after a pause. A new app still starts when none is running, for the first activity or after one finished.
  • A fullscreen app makes the new activity fullscreen in activityOnCreate, before its window opens, as run does for the first one. Left to the next resume, the switch came after the window opened, and on Android 15 the 3-button navigation bar stayed opaque over the app until it was paused and resumed. The fullscreen flag moves from the render thread's state to an atomic so the UI thread can read it.

The Java side is unchanged: QuadNative keeps its signatures.

Verification

On the Android 15 emulator (API 35, 3-button navigation), with a macroquad game (CHOMP) whose activity doesn't handle font scale or locale changes:

  • Before: changing the font scale while the game was in the background, then bringing it back, aborted the process. On the emulator, CHOMP's own JNI code aborted first. On a Pixel 6 (Android 17), with that worked around, the new render thread aborted as above.
  • After: changing the font scale in the background and in the foreground, changing the app's language with cmd locale set-app-locales, and leaving and reopening the game with "Don't keep activities" on all keep the same process and bring the game back as it was: same screen, same position, undo history intact, input working. The navigation bar stays see-through.
  • Removing the task from Recents still finishes the activity and ends the process.
  • cargo clippy --target aarch64-linux-android adds no warnings.

🤖 Generated with Claude Code

Android destroys an activity and creates a new one in the same process
after a configuration change the activity doesn't handle itself, such
as a new font size or language, and under the "Don't keep activities"
developer option. `activityOnDestroy` quit the app, and the next
`activityOnCreate` called `quad_main` again, starting a second app in
the process that kept the first one's globals. A macroquad app crashed
there, freeing GL objects made under the first app's context.

`Destroy` now quits only when the activity is finishing. Otherwise the
app keeps running, as it does in the background, and the next
activity takes it over: `activityOnCreate` hands its global reference
to the render thread, which swaps it into `ACTIVITY` and deletes the
old one, so calls such as `setFullScreen` reach the activity on screen.
Its surface arrives through the usual `surfaceCreated`, as after a
pause. A new app still starts when none is running.

A fullscreen app makes the new activity fullscreen in
`activityOnCreate`, before its window opens, as `run` does for the
first one. Left to the next resume, the switch came after the window
opened, and on Android 15 the 3-button navigation bar stayed opaque
over the app until it was paused and resumed. The fullscreen flag
moves from the render thread's state to an atomic so the UI thread
can read it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
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.

1 participant

0