No More DisposableEffect Hacks: The Magic of Modifier.keepScreenOn()

 How Jetpack Compose 1.9+ finally simplified screen-awake logic with a single, lifecycle-aware modifier.

No More DisposableEffect Hacks: The Magic of Modifier.keepScreenOn()

For years, Android developers have shared a collective minor headache: keeping the screen awake. Whether for a navigation app, a recipe guide, or a media player, we’ve had to wrestle with the imperative Window API.

With the arrival of newer versions of Jetpack Compose (around 1.9+), the struggle for Android keep screen awake scenarios is finally over. Enter Modifier.keepScreenOn()—the simple API that brings a massive quality-of-life upgrade to the declarative world.

The “Old Way”: A Ritual of Manual Management

Before this update, preventing a device from dimming required stepping out of the Composable world and back into the Activity lifecycle. This approach was error-prone and easy to misuse, especially when it came to ensuring the flag was cleared during lifecycle transitions.

📊 Old vs. New: At a Glance

Press enter or click to view image in full size
Old vs. New: At a Glance
Old vs. New: At a Glance

The Modern Solution: Elegant & Declarative

In the latest Compose releases, keeping the screen active is now as simple as a single modifier. It abstracts away the FLAG_KEEP_SCREEN_ON handling into a lifecycle-aware wrapper.

// ✅ The modern "After" approach
@Composable
fun CookingStepScreen(recipe: Recipe) {
Column(
modifier = Modifier
.fillMaxSize()
.keepScreenOn() // Minimal, safe, and clean.
) {
Text(text = recipe.currentStep)
}
}

Pro-Tip: Implementing Conditional Wakefulness

You shouldn’t always keep the screen on. Use Compose state to toggle the modifier only when active engagement is required:

@Composable
fun WorkoutScreen(isActive: Boolean) {
// We only apply the modifier when the workout is actually running
val wakeModifier = if (isActive) Modifier.keepScreenOn() else Modifier

Box(modifier = Modifier.fillMaxSize().then(wakeModifier)) {
Text("Workout in progress: $isActive")
}
}

⚠️ When You Should NOT Use Modifier.keepScreenOn()

While powerful, this is not a “set and forget” tool for every screen. Avoid using it for:

  • Background Tasks: If your app needs to do work while the screen is off (like downloading a file), use a WorkManager or a traditional WakeLock.
  • Passive Screens: Splash screens or login pages don’t need to override the user’s system timeout.
  • Battery-Critical Apps: If your app is already heavy on resources, keeping the screen on indefinitely can lead to poor user reviews regarding battery drain.

🚫 Common Mistakes to Avoid

  1. Applying it to the Root Theme: Don’t wrap your entire MaterialTheme in this modifier. It forces the screen to stay on for the entire app, which is a major UX anti-pattern.
  2. Assuming it works in the Background: Remember, this is a UI modifier. If the user hits the Home button, the Composable leaves the composition, and the screen-on flag is cleared.
  3. Ignoring System Low-Power Mode: While this flag overrides the timeout, the system may still choose to ignore it if the device is in an extreme battery-saver state.

🧠 Technical Nuance: Under the Hood

Modifier.keepScreenOn() is a Compose-friendly wrapper for WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON.

Compose ensures the flag remains active as long as at least one visible Composable requests it. Like its View-system counterpart (view.keepScreenOn = true), this only applies while the app is in the foreground and the UI is visible.

🙋 Frequently Asked Questions (FAQs)

Does this replace the PowerManager WakeLock?

For UI-driven scenarios, yes. It is the preferred way to keep the screen on while the app is visible. However, WakeLock is still required for background processing when the screen is dark.

Does this require special permissions?

No. Unlike WakeLock, using window flags does not require the WAKE_LOCK permission in your AndroidManifest.xml.

Is it battery-efficient?

Yes. Because it is tied strictly to the visibility of the Composable, the risk of “leaking” a wake state into other parts of the app is virtually eliminated.

🔚 Final Thoughts

Modifier.keepScreenOn() is a small API with a big impact. It removes boilerplate, improves safety, and aligns perfectly with the declarative philosophy of Jetpack Compose. For most UI-driven use cases, this should now be your default choice.

💬 Let’s Discuss!

  • Are there other “Window” flags you’d like to see turned into Modifiers?
  • What’s the most creative use case you’ve found for keeping a screen awake?
  • Do you prefer this over the old DisposableEffect approach?

Drop your thoughts in the comments below!

📘 Master Your Next Technical Interview

Since Java is the foundation of Android development, mastering DSA is essential. I highly recommend “Mastering Data Structures & Algorithms in Java”. It’s a focused roadmap covering 100+ coding challenges to help you ace your technical rounds.

Comments

Popular posts from this blog

No More _state + state: Simplifying ViewModels with Kotlin 2.3

Why You Should Stop Passing ViewModels Around Your Compose UI Tree 🚫

Is Jetpack Compose Making Your APK Fatter? (And How to Fix It)