When you implement a dark mode toggle in Android, the typical flow is: save the setting, restart the Activity, and have the theme applied. Most sample code uses recreate() for this purpose. In my wallpaper app, which I've been maintaining for over 12 years with 50M+ cumulative downloads, this exact pattern was causing intermittent white screen flashes for some users.
The lesson I've taken from long-running indie app development: bugs are usually symptoms of a deeper design problem. The white screen was telling me something was off about how I was handling Activity recreation in the presence of SDK initialization and heavy image loading.
Why recreate() Causes a White Screen
When recreate() is called, Android destroys the current Activity and creates a new one. The problem is that there's a brief moment between destruction and creation when nothing is rendered — and that gap can become visible.
The conditions that make this noticeable are:
- Activities that load heavy assets at startup (wallpaper apps are a prime example)
- Lower-spec devices or older Android versions (6 through 8)
- SharedPreferences written with
apply()instead ofcommit()— the setting may not be flushed before the Activity restarts
In my case, users of Beautiful HD Wallpapers began reporting brief white flashes during theme changes. The reproduction condition was narrow enough that I couldn't easily catch it myself, which is exactly the kind of bug that lingers in negative reviews for months.
The AppRestarter.safeRestart Pattern
The fix came from rethinking the scope of the restart. Instead of relying on recreate(), which only restarts the current Activity, I moved to a pattern that restarts the entire app process.
// AppRestarter.kt
object AppRestarter {
fun safeRestart(context: Context, delayMs: Long = 300L) {
val intent = context.packageManager
.getLaunchIntentForPackage(context.packageName)
?.apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
}
?: return
Handler(Looper.getMainLooper()).postDelayed({
context.startActivity(intent)
android.os.Process.killProcess(android.os.Process.myPid())
}, delayMs)
}
}The call site is clean and explicit:
// SettingsActivity.kt
fun applyTheme(isDark: Boolean) {
// Use commit() to guarantee the write before restart
prefs.edit().putBoolean("dark_mode", isDark).commit()
AppRestarter.safeRestart(this)
}recreate() vs. safeRestart: The Real Difference
recreate() restarts only the current Activity. When your app has complex Fragment hierarchies, ViewModel state, or third-party SDKs initialized at the Application level, there's no guarantee that everything lands in a clean state after recreation.
In my wallpaper app, AdMob was being initialized early in the Activity lifecycle. After recreate(), the SDK occasionally landed in a state where it had already received initialization callbacks but the UI hadn't fully rebuilt. This race condition produced the white flash.
AppRestarter.safeRestart() restarts the entire process, which means Application.onCreate() runs again from scratch. Every SDK starts clean. No partial states.
The User Experience Trade-off
Switching to safeRestart means that when a user changes the theme, the app visibly restarts rather than instantly toggling. There's a brief return to the launcher before the app comes back with the new theme applied.
Whether this feels natural depends on the app. For a wallpaper app, theme switching is a rare, deliberate action. A clean restart actually feels more intentional than a brief white flash. After shipping this fix in v2.1.0, the complaint rate around theme switching in user reviews dropped noticeably.
If 300ms isn't enough delay on your target devices, extending to 500ms is safe.
Applying This to Rork Max Projects
When Rork Max generates an Android project, theme management typically goes through Context or a Theme Provider. If you're building a production app with Rork and want to implement theme switching reliably, here's what to verify before shipping:
- Confirm the Activity extends
AppCompatActivity - Check whether theme preferences are stored in SharedPreferences or Jetpack Datastore
- Look at where SDK initialization (AdMob, Firebase, etc.) happens — is it in
Application.onCreate()or the Activity?
Rork-generated settings screens tend to implement theme switching with recreate() or equivalent behavior by default. For production use, it's worth refactoring to the safeRestart pattern before launch.
Building Apps That Last
My late grandfathers were both temple carpenters. The belief I grew up watching them practice was that craftsmanship applied to things meant to last is itself a form of devotion. That sensibility carries into how I approach app maintenance.
recreate() works on most devices most of the time. But collecting user reviews over time and noticing a pattern of "occasional white screen" reports is how you find the problems that device testing in ideal conditions will never surface.
This is true whether you're writing Android code from scratch or building with Rork. The quality comes from the small, careful fixes — understanding why something works the way it does, and choosing the approach that holds up under real conditions.
If you're seeing white screen reports related to theme switching, start by looking at recreate() and how SharedPreferences writes are timed around it. That's where the answer usually is.