Implementing the Splash Activity in Android - The Right Way - Truiton
Skip to content

Implementing the Splash Activity in Android – The Right Way

Android Splash Screen API

If you are working on a large scale Android app, you might realize that to give a premium experience to your users you need to implement a splash activity in Android. In most cases behind the scenes a splash screen is used to load data in background and on the foreground it is utilized to educate users about the app. In terms of implementation, when an app is starting, specially in a cold start case a lot of activity is done by the Android OS to start your app. To optimize this and give a great experience to the users, android has introduced a Splash Screen API. In this tutorial lets see how the new android splash screen API is used and its benefits.

What’s the use of new Android Splash Screen API ?

You might start to think what’s the use of this new Android SplashScreen API? We can always build a custom splash screen and use it as per requirement. To understand the actual use of this API we must first understand what’s a cold start for an Android app. To understand this lets go little deeper. A cold start means launching an app for the first time. It refers to a state of OS starting an app when its process is not running. When launching an android app for the first time, OS does a lot of work in the background and creating its process from the scratch is called a cold start. Lets have a look at the states an app goes through before actually starting.

Android Splash Screen Cold Start

As per the official documentation first OS starts loading and launching the app then displays a blank screen momentarily, then finally the handoff happens to the apps process where our code can actually be executed. Now from an experience standpoint even if you have a custom splash screen for launch, it would be displayed only after a blank screen is displayed momentarily. You might not get to see this experience on very fast devices, but it exists. Starting Android 12 we have this new Splash Screen API which shows a standardized splash screen, avoiding the original blank screen before the handoff to app’s process. This gives a much better experience to the user in comparison to the blank container.

Interestingly this new Android Splash Screen API is applied by default on all the apps from Android 12. Therefore whenever you launch an app on Android 12 and above you will always see a standardized animation and then your original splash screen would be displayed. This could be a little abrupt if you have used android:windowBackground, in your theme. As the standardized Android splash activity uses your app’s launcher icon and theme’s android:windowBackground, attribute to show a splash screen. To make this standardized experience blend into your app’s experience, android team has exposed some basic level of functionalities in this API, which can be used to customize your app’s launch experience. In the next section I will show an Android SplashScreen API example for the same.

This new Android SplashScreen API has been introduced from Android 12, but a compat version of the same has also been released, which allows us to use this from API 21 onwards. In our Splash Activity in android tutorial we will be using the same. To use the compat version please include this in your gradle file :

implementation "androidx.core:core-splashscreen:1.0.0"

Implementation of Splash Activity in Android

In a large scale production app, there’s a good chance that you might need to implement an Android Splash Screen. In this section we will implement the same using the latest Android SplashScreen API. As mentioned in the previous section, default Android’s splash screen gives us a very standardized implementation of the splash screen. Where your app’s launcher icon and android:windowBackground, is used to show a splash screen. If we are building a large scale app we might need to customize it according to our needs. If we have to build a splash activity in Android using the latest API, it gives us all the powers to customize it. Have a look at the animation below, this is what we will try to achieve in our app.

Android Splash Screen – Cold Start

Although as per official documentation it is advised that our apps launcher screen should be the actual main screen where the user has intended to go. But when building large scale apps a splash screen is needed to do various things like, initializing SDKs (if not in the Application class), fetching location before the main screen or maybe just to build a deep link router, there are many more such use cases (If you know a few, please add them in the comments section). Therefore in this section we will build a splash screen which would have the default enter animation with the screen customization according to our theme, and a custom exit animation which would transform the initial splash in to our custom android splash screen. In this custom splash activity we can do whatever we want, once we execute our code we will eventually load app’s main screen.

Please note – If this is not your use case and you wish to open the main screen directly, things are simpler for you. Splash screen just needs to be initialized as per the official documentation.

Firstly to start with building a splash screen in Android Studio we need to include a Gradle dependency defined in the section above, this way we will have the support from android API 21 onwards. Next we need to create a theme which inherits the "Theme.SplashScreen". Have look at the example code:

<style name="Theme.MyCustomSplash" parent="Theme.SplashScreen">
    <item name="windowSplashScreenBackground">@color/purple_500</item>
    <item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item>
    <item name="postSplashScreenTheme">@style/Theme.MyCustomSplashTheme</item>
</style>

<style name="Theme.MyCustomSplashTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <item name="colorPrimary">@color/purple_500</item>
    <item name="colorPrimaryVariant">@color/purple_700</item>
    <item name="colorOnPrimary">@color/white</item>
    <item name="colorSecondary">@color/teal_200</item>
    <item name="colorSecondaryVariant">@color/teal_700</item>
    <item name="colorOnSecondary">@color/black</item>
    <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
    <item name="android:windowActionBar">false</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:fitsSystemWindows">false</item>
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowContentOverlay">@null</item>
    <!-- Customize your theme here. -->

</style>

In the above section another point to note is that we also have to define a postSplashScreenTheme attribute, where we mention the theme which is to be applied after the standardized splash animation is dismissed. In our case since we are landing the user on to a custom android splash screen, we have mentioned a theme which is inheriting "Theme.MaterialComponents.DayNight.NoActionBar". Otherwise we could have used the app’s theme. Next lets have a look at the manifest where this theme needs to be specified, although in the end of this article, I will share the link to its full source code.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyCustomAppTheme">
        <activity
            android:name=".MyLaunchActivity"
            android:exported="true"
            android:theme="@style/Theme.MyCustomSplash">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".MainActivity" />
    </application>

</manifest>

As you can see in our launch activity we have defined the our custom Android Splash Screen theme. Next we have to do an initialization of the SplashScreen API in the onCreate of launch activity. Please note that this needs to be done before super.onCreate and setContentView.

package com.truiton.splashscreenapi

import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.animation.AccelerateInterpolator
import android.view.animation.OvershootInterpolator
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.animation.doOnEnd
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext


class MyLaunchActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val screen = installSplashScreen()
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_launch)
        val mySplashMainIcon: ImageView = findViewById(R.id.splash_main_icon)
        screen.setOnExitAnimationListener { splashScreenView ->
            val lineStartY: Int = getRelativeTop2(mySplashMainIcon)
            val animY = ObjectAnimator.ofFloat(
                splashScreenView.iconView,
                View.Y,
                lineStartY.toFloat()
            )
            //Just in case you wish to run multiple animations
            /*val animX = ObjectAnimator.ofFloat(
                splashScreenView.iconView,
                View.X,
                mySplashIcon2.x
            )*/

            val alpha = ObjectAnimator.ofFloat(
                splashScreenView.view,
                View.ALPHA,
                1f,
                0f
            )
            alpha.interpolator = AccelerateInterpolator()
            alpha.duration = 200L

            val traverseSet = AnimatorSet().apply {
                interpolator = OvershootInterpolator()
                duration = 500L
                playTogether(/*animX,*/ animY)
            }

            AnimatorSet().apply {
                play(traverseSet).before(alpha)
                doOnEnd {
                    splashScreenView.remove()
                }
                start()
            }
        }

        lifecycleScope.launch(Dispatchers.Main) {
            doSomeWork() // can do initializations on IO/Worker Thread
            launchNextScreen() // back on UI/Main thread
        }
    }

    private suspend fun doSomeWork() = withContext(Dispatchers.IO) {
        delay(5000L) // pretend we are doing some IO operation
    }

    private fun launchNextScreen() {
        startActivity(Intent(this, MainActivity::class.java))
        finish()
    }

    private fun getRelativeTop2(view: View): Int {
        val parent = view.parent as View
        val parentLocation = IntArray(2)
        val viewLocation = IntArray(2)
        view.getLocationOnScreen(viewLocation)
        parent.getLocationOnScreen(parentLocation)
        return viewLocation[1] - (parentLocation[1]*2)
    }
}

To make a splash screen exit animation on Android we have overridden setOnExitAnimationListener. This callback gives us a reference to the splash screen view through which we can get the logo view which can be used for animation. So to animate we have used an ObjectAnimator, the code for the same is self explanatory and beyond the scope of this article. You can view full source code here:

Now once this setOnExitAnimationListener has completed its execution we land into the regular app flow, where we have started a coroutine which is pretending to to some work, in the actual implementation you can write all the initializations or API calls that you want to make in this doSomeWork() method. Once the execution for doSomeWork() method completes this coroutine launches the next activity of the app giving us the desired Android custom splash screen experience.

When building this sample I also did CPU and memory profiling of the custom splash activity in the sample. Interestingly when we launch the app for the first time, basically when we do a cold start it does give a spike, since OS is loading and launching the app but there is no visual lag, neither there is any blank screen momentarily. This is the real advantage of using the Android SplashScreen API. Also when we do a warm start of the app, you can see that the handoff from splash to custom animation happens almost instantaneously, and since we have a setOnExitAnimationListener set to handle this situation it works flawlessly giving a very smooth experience. This brings us to the conclusion of this article, hope it helped in understanding the concept.


Leave a Reply

Your email address will not be published. Required fields are marked *