Android Splash Screen API vs Compose Splash Screen: Which Should You Use in 2026?
The Android Splash Screen API has been the recommended way to implement splash screens since Android 12. But a growing number of developers are questioning whether it’s the right choice for every app. Some have abandoned it entirely, implementing custom splash screens in Jetpack Compose instead. Here’s what you need to know to make the right decision.
The Problem
The Android Splash Screen API comes with significant constraints that can frustrate developers:
1. Requires XML theme configuration -> Even for Compose-only apps -> postSplashScreenTheme must reference XML theme
2. Limited customization -> Fixed icon positioning -> No custom animations beyond the icon -> Background must be solid color or drawable
3. OEM-specific bugs -> Samsung: Sometimes ignores animation duration -> Xiaomi: Icon scaling issues -> Huawei: Race conditions with theme transition
4. Cannot reliably perform async operations -> setKeepOnScreenCondition is a polling API -> No true async/await support -> Data loading must complete elsewhereA Reddit discussion on r/androiddev captured the frustration:
“Splash Screen API is terrible and no one cares.”
This controversial take sparked a debate. Some developers have worked around the API entirely, implementing a Compose splash screen with NavHost instead.
The Direct Answer
For most Jetpack Compose apps, the Android Splash Screen API is still the recommended approach despite its limitations. It provides platform compliance, consistent user experience, and follows Android design guidelines.
However, consider a Compose-based splash screen if:
- You need full control over splash behavior and animations
- You’re hitting OEM-specific bugs that break the splash experience
- You have complex navigation requirements (deciding logged-in state on cold-start)
- Your app requires authentication checks before showing any UI
Three Options Compared
Option A: Android Splash Screen API (Recommended for Most Apps)
This is the standard approach that follows Android platform guidelines.
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { val splashScreen = installSplashScreen()
super.onCreate(savedInstanceState)
// Keep splash visible while checking auth var isReady = false splashScreen.setKeepOnScreenCondition { !isReady }
lifecycleScope.launch { // Check authentication state val isLoggedIn = authRepository.checkAuthStatus() isReady = true
setContent { AppTheme { if (isLoggedIn) { HomeScreen() } else { LoginScreen() } } } } }}Pros:
- Platform-compliant
- Consistent with Android design guidelines
- Handles cold start automatically
- Supports launch animations
Cons:
- Limited customization
- Requires XML theme configuration
- OEM compatibility issues
- Cannot perform real async operations during splash
Option B: Compose Splash Screen with NavHost
For apps needing more control, implement splash entirely in Compose:
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)
setContent { AppTheme { val navController = rememberNavController() val startDestination by produceState<SplashDestination> { value = SplashDestination.Checking }
NavHost( navController = navController, startDestination = "splash" ) { composable("splash") { SplashScreen( onAuthDetermined = { isLoggedIn -> if (isLoggedIn) { navController.navigate("home") { popUpTo("splash") { inclusive = true } } } else { navController.navigate("login") { popUpTo("splash") { inclusive = true } } } } ) } composable("home") { HomeScreen() } composable("login") { LoginScreen() } } } } }}@Composablefun SplashScreen( onAuthDetermined: (Boolean) -> Unit) { val authRepository = LocalAuthRepository.current
LaunchedEffect(Unit) { val isLoggedIn = authRepository.checkAuthStatus() delay(500) // Optional: minimum splash duration for branding onAuthDetermined(isLoggedIn) }
Box( modifier = Modifier .fillMaxSize() .background(MaterialTheme.colorScheme.primary), contentAlignment = Alignment.Center ) { // Custom splash UI Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Image( painter = painterResource(id = R.drawable.logo), contentDescription = "App Logo", modifier = Modifier.size(120.dp) ) Spacer(modifier = Modifier.height(16.dp)) CircularProgressIndicator( color = MaterialTheme.colorScheme.onPrimary ) } }}Pros:
- Full control over UI and animations
- Natural integration with Compose Navigation
- Easy to add custom loading states
- No XML required
Cons:
- No platform launch animation
- Slight delay before Compose initializes
- Must handle theme for Activity window
- Not following Android splash guidelines
Option C: Hybrid Approach
Combine both approaches to get platform compliance with Compose flexibility:
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { val splashScreen = installSplashScreen()
super.onCreate(savedInstanceState)
// The platform splash shows during Compose initialization // Then transitions to your Compose splash for auth/loading
setContent { AppTheme { val navController = rememberNavController() var showPlatformSplash by remember { mutableStateOf(true) }
// Dismiss platform splash once Compose is ready LaunchedEffect(Unit) { splashScreen.setKeepOnScreenCondition { false } }
NavHost( navController = navController, startDestination = "compose_splash" ) { composable("compose_splash") { ComposeSplashScreen( onReady = { destination -> navController.navigate(destination) { popUpTo("compose_splash") { inclusive = true } } } ) } // ... other destinations } } } }}The challenge with hybrid: Avoiding the “2x splash” problem where users see two splash screens in sequence.
// WRONG: Platform splash shows, then Compose splash shows againsetContent { SplashScreen() // User sees splash twice}
// CORRECT: Platform splash transitions directly to contentsetContent { // Platform splash already handled the branding moment // Go directly to auth check or main content AuthGate()}Comparison Table
| Feature | Splash Screen API | Compose Splash | Hybrid |
|---|---|---|---|
| Platform compliance | Full | None | Full |
| Custom animations | Limited | Unlimited | Limited |
| XML required | Yes | No | Yes |
| OEM compatibility | Variable | Consistent | Variable |
| Auth flow support | Basic | Full | Full |
| Cold start handling | Automatic | Manual | Automatic |
| Implementation complexity | Low | Medium | High |
| Design flexibility | Low | High | Medium |
Common Mistakes
Mistake 1: Assuming the API Will Wait for Data Loading
splashScreen.setKeepOnScreenCondition { // This is polled, not awaited !dataRepository.isDataLoaded() // May never complete}The setKeepOnScreenCondition is a polling API. It doesn’t pause execution. Complex data loading should happen after the splash dismisses.
Mistake 2: Ignoring OEM Testing
Some device manufacturers modify splash screen behavior. Always test on:
- Samsung devices (OneUI)
- Xiaomi devices (MIUI/HyperOS)
- Huawei devices (EMUI)
- OnePlus devices (OxygenOS)
Mistake 3: Creating 2x Splash Unintentionally
// In themes.xml<style name="Theme.App.Splash" parent="Theme.SplashScreen"> <item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item></style>
// In MainActivity.ktsetContent { SplashScreen() // User sees platform splash, then this}Mistake 4: Over-Engineering with Compose Splash
If your app doesn’t need authentication checks or complex initialization, stick with the platform API. A simple splash is often better than a custom one.
// Simple use case: Just show app iconinstallSplashScreen()setContent { AppTheme { HomeScreen() } }
// Complex use case: Auth + data loading// -> Consider Compose splash with NavHostMistake 5: Skipping the API Entirely for New Apps
For new apps, start with the platform API. Only switch to a custom solution if you hit specific limitations.
When to Use Which Approach
Use Android Splash Screen API when:-> Your app has simple initialization needs-> You want platform compliance-> You don't need complex auth flows during splash-> You're starting a new project
Use Compose Splash Screen when:-> You need full UI control-> Auth state determines initial destination-> You've hit OEM bugs with the platform API-> Your splash has complex animations
Use Hybrid when:-> You need platform compliance AND auth flows-> You want smooth transition from platform to Compose-> You're willing to handle the complexityThe Authentication Flow Pattern
The most common reason developers choose Compose splash is authentication:
@Composablefun AuthGate( navController: NavHostController, authRepository: AuthRepository) { val authState by authRepository.authState.collectAsState()
LaunchedEffect(authState) { when (authState) { AuthState.LoggedIn -> { navController.navigate("home") { popUpTo("splash") { inclusive = true } } } AuthState.LoggedOut -> { navController.navigate("login") { popUpTo("splash") { inclusive = true } } } AuthState.Loading -> { // Stay on splash } } }}This pattern is clean with Compose Navigation but awkward with the platform Splash Screen API because the API doesn’t support async decision-making naturally.
Summary
The Android Splash Screen API is the right choice for most apps. It’s platform-compliant, handles cold starts automatically, and follows Android design guidelines.
However, if your app has complex authentication flows, needs full UI control, or you’re hitting OEM-specific bugs, a Compose-based splash screen with NavHost is a valid alternative.
Key takeaways:
- Start with the platform API for new apps
- Use
setKeepOnScreenConditionfor simple initialization checks - Consider Compose splash when auth state determines initial destination
- Test on multiple OEM devices
- Avoid the “2x splash” problem with hybrid approaches
- Don’t pre-load data expecting it to complete during splash
Choose the approach that fits your app’s specific requirements, not what’s “recommended” in the abstract.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Reddit: Splash Screen API Discussion on r/androiddev
- 👨💻 Android Splash Screen API Documentation
- 👨💻 androidx.core:splashscreen Library
- 👨💻 Jetpack Compose Navigation
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments