Android Splash Screens Done Right

Update 2013-06-25: The technique described in this article is a bit outdated since the introduction of Fragments into Android. To read more about using a Fragment for a splash screen, see How To Handle Common UI Components, a free chapter of my book Android User Interface Design: Turning Ideas and Sketches into Beautifully Designed Apps.

I’ve never been a big fan of splash screens, especially for mobile apps, because people often add them in as a means of throwing branding in your face. It’s like when you play a video game and you have to watch the 10 second video clip by the studio, and then the clip for the game engine, and then the clip for the producer, and then the clip for the lead designer’s dog, and then you finally get to the loading screen that you sit at before eventually being allowed the luxury of accessing the main menu. The point of a splash screen is to show something to the user while loading is in progress. The minimum amount of loading necessary to show a usable UI should be done, and then the splash screen should be gone. Rarely should this ever be more than a few seconds. I recently had to implement a splash screen and, after getting halfway through a solution, I decided to see how other people tackled the problem.

I was appalled to see all the examples of creating an Activity that has an artificial delay before starting the real Activity. Worse, many of them started timers that weren’t canceled when the app lost focus, so they would still start the app if you had backed out of the splash screen and started doing something else. Some even created Threads to put to sleep and then called the stop method on them. The purpose of a splash screen is to give the user an indication that your app is loading–not to create an extra delay before the user can load your app. People don’t like waiting, especially in a mobile environment.

Alright, so what’s the “right” way of doing a splash screen? I recommend waiting until you have a pretty well developed app before even considering the splash screen. For at least half of apps, you won’t even need one. Android apps tend to be light weight and very fast, often presenting a usable interface within a second of tapping on the icon. If you do genuinely need more time, then chances are you are making use of AsyncTasks or Handlers or other methods of putting your long-running code on a separate thread (if you’re not, then you’re doing it wrong). You just need to display the splash screen in your onCreate method and remove it in your AsyncTask’s onPostExecute method, your Handler’s handleMessage method, etc.

I have found that the best method of displaying a splash screen is with a simple Dialog. It’s been in Android since pre-1.0 and is extremely easy to use. You can pass it any layout you want, even with a custom theme. Here’s an example:

/**
 * Simple Dialog used to show the splash screen
 */
protected Dialog mSplashDialog;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    MyStateSaver data = (MyStateSaver) getLastNonConfigurationInstance();
    if (data != null) {
        // Show splash screen if still loading
        if (data.showSplashScreen) {
            showSplashScreen();
        }
        setContentView(R.layout.yourmainlayout);        

        // Rebuild your UI with your saved state here
    } else {
        showSplashScreen();
        setContentView(R.layout.yourmainlayout);
        // Do your heavy loading here on a background thread
    }
}

@Override
public Object onRetainNonConfigurationInstance() {
    MyStateSaver data = new MyStateSaver();
    // Save your important data here

    if (mSplashDialog != null) {
        data.showSplashScreen = true;
        removeSplashScreen();
    }
    return data;
}

/**
 * Removes the Dialog that displays the splash screen
 */
protected void removeSplashScreen() {
    if (mSplashDialog != null) {
        mSplashDialog.dismiss();
        mSplashDialog = null;
    }
}

/**
 * Shows the splash screen over the full Activity
 */
protected void showSplashScreen() {
    mSplashDialog = new Dialog(this, R.style.SplashScreen);
    mSplashDialog.setContentView(R.layout.splashscreen);
    mSplashDialog.setCancelable(false);
    mSplashDialog.show();
    
    // Set Runnable to remove splash screen just in case
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
      @Override
      public void run() {
        removeSplashScreen();
      }
    }, 3000);
}

/**
 * Simple class for storing important data across config changes
 */
private class MyStateSaver {
    public boolean showSplashScreen = false;
    // Your other important fields here
}

In the onCreate method, you call getLastNonConfigurationInstance() to get any data that you saved in onRetainNonConfigurationInstance() (if you don’t know what those are, read Faster screen orientation change now!). If you have data and were still loading when the config change was triggered, show the splash screen and continue any loading you need to do. If there is no saved data, show the splash screen and start your long-running processes. In either case, the main layout is set after checking if the splash screen needs to be shown.

The removeSplashScreen method is safe to call at any point because it checks the mSplashDialog for null before dismissing and then removing the reference. Since you will only ever show the splash screen once per Activity lifecycle, there is no reason to keep a reference to it. This is the method you would call in your AsyncTask’s onPostExecute method, your Handler’s handleMessage method, etc.

The showSplashScreen method creates a new Dialog with a custom theme, sets the view to your layout defined in XML (this can look however you want and include progress indicators, but keep the layout relatively simple and verify it with hierarchyviewer), prevents the Dialog from being canceled, and then shows the Dialog. If you need to show the splash screen for more than a couple of seconds, you should catch presses of the back button to finish your Activity. This method also schedules a call to removeSplashScreen() for three seconds later, so the splash screen will go away either when the removeSplashScreen method is called from the long-running task finishing or from the time running out. You can choose to not include this, but you definitely want to handle the back button in that case.

In your res/values/styles.xml file, you might have something like this:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="SplashScreen">
        <item name="android:padding">0dp</item>
        <item name="android:windowBackground">@android:color/black</item>
        <item name="android:windowFrame">@null</item>
    </style>
</resources>

Obviously, you can customize that to look right for your app, but that gives you an idea for a simple full screen dialog.

That’s all there is to creating a functional splash screen for your Android app. If you’re having problems getting the splash screen to appear, verify that your long-running task is not running on the UI thread (it should not simply be in onCreate but should instead be executed on another thread). If you know any way to improve this or any alternate methods, feel free to add your knowledge in the comments. If you have a question specific to this code, you can ask as well, but questions that veer much from this should be asked somewhere like StackOverflow, where you’ll get a lot more eyes on your question a lot faster. Happy New Year!

About Ian G. Clifton

Ian currently works as the Director of User Experience for A.R.O. in Seattle, WA where he also leads Android development. Previously, he has worked as an Android developer, web developer, and even a Satellite, Wideband, and Telemetry Systems Journeyman in the United States Air Force. He has created the Essentials of Android Application Development LiveLessons video series and has just finished his first book, Android User Interface Design: Turning Ideas and Sketches into Beautifully Designed Apps. He spends his off time on photography, drawing, developing, and doing technical review for other Android developers. You can follow his posts on this blog or his ramblings on Twitter.
This entry was posted in Code Samples and tagged , , , . Bookmark the permalink.

61 Responses to Android Splash Screens Done Right

  1. Steve says:

    Thanks Ian, I’ve been looking around for about an hour for a good Splash Screen example and have the same issue with a lot of them. Only splash only if your app absolutely needs to, make it quick and show some indication of progress if it’s more than a couple of seconds (and who still thinks using Thread.stop() is a good idea). Thanks for the example.

    • Glad you found it useful. Yeah, I was definitely surprised at how poorly the articles I came across implemented splash screens. People using Thread.stop() was the biggest surprise though, and it was often just a thread that was created for timing instead of simply using a Handler.

  2. Mal says:

    Hi Ian,
    thank you for posting up solution here, I am very new to android development i have trouble integrating ur sample codes into my project.

    A quick question do i have to create a new activity for the splash screen?

    • In most cases you can simply add the splash screen dialog to your existing main Activity. This gives you the advantage of being able to directly use any data that you have to prepare or load rather than having to pass it from a splash screen Activity into another Activity.

  3. yogeshr says:

    Thx for the simple splash screen suggestion. Exactly what I was looking for, keep up the good work.

  4. Stephen says:

    Thank you for your post. I got a question. When I start my app in the landscape mode the splashscreen doesn’t fit into screen. Do I have to create a separate xml for landscape mode? How do I do that? Thanks.

  5. Stephen says:

    I have solved the issue. I have created a new xml for the dialog and placed it in the layout-land folder. Thanks.

  6. Stephen says:

    Would it be a good idea to move code from line 21 and 16 to line 9.

    • The main reason for not doing that is because you may have a relatively complex layout that is being loaded. If that’s the case, it’s much better to show the loading dialog and then load the main layout behind that. Otherwise you can end up with a bit of a delay before the loading dialog is even shown.

      • Jozi says:

        Well, the problem here is that the dialog won’t be shown anyway before onCreate() returns – just confirmed that behaviour with Android 2.3.

        Even with most(all?) GUI frameworks, drawing will happen independently from showing/hiding or invalidating something.

  7. Dennis says:

    Nice code!, thanks for posting it.

    Been busy with it few days now, and I can’t get it to work. I’ve just started to dev for droid, so this might be a stupid question;

    No matter what I do, the ‘splash screens’ stays one big black nothing for me… :( There are some basic that I’m missing, again, I’m busy with it for a few days now, comparing your example with the google documentation for (custom) dialog’s.

    But here’s the main quesiton;
    I’ve made a layout, in the ‘res\layout’ folder, and when I look at it in the graphical layout tap, I get what I want, just a picture. It doesn’t matter, if I leave out the style like;
    mSplashDialog = new Dialog(this);

    And why don’t you ever do a;
    setContentView(R.layout.splashscreen);

    Dispite the black screen, my application does go on processing the 3000 json items and setting up the overlays for my mapview, and when it done, it does show my mapview. So that part does work for me…

    Thanks,

    Dennis

    • Hi Denis,

      I would first verify that everything, including the standard UI, works without the Dialog. Then add back the Dialog code. If you still see a black screen for a splash screen instead of your custom layout, change the dialog.setCancelable call to pass true and try pressing the device’s back button while the blank screen is visible. If it goes away and you see the regular UI, your dialog itself is problematic (maybe the layout). If your app just closes, it may be an issue with the main UI or the call to display the Dialog itself. You can also try changing the windowBackground of the splash screen to red or another color to verify that you are seeing that much, and it’s a good idea to check hierarchyviewer to see what Views are actually being loaded and where.

      The reason for not calling setContentView with the splash screen layout is because you want to load the actual layout behind the splash screen. The setContentView method loads the specified layout into the FrameLayout provided to your app by the OS. By loading the Dialog first and then calling setContentView with your real layout, you let the system immediately show the dialog while building your real UI in the background. If you set your splash screen layout with setContentView, then you have to figure out how/where you will load your real UI, probably causing flashing during the transition from loading screen to usable screen.

  8. Dennis says:

    -In the style I changed the background color to white;
    @android:color/white

    -I’ve set the cancalable to true;
    mSplashDialog.setCancelable(true);

    When I run my program, the screen stays black, nothing to see, nothing white… :( When I press the back button during loaging (the black screen), a dialog appears that my application is not responding (because it’s busy doing the JSON loading/pasring). If you wait that out, you get my mapview afther about 20 seconds later. My program runs fine after that.

    Thanks again!

  9. Dennis says:

    Done some more testing, probally missed something stupid.
    -I’ve made the most simple helloandroid test app;
    -Included a splashlayout layout
    -Included a styles.xml file
    -Run it, same result, 5 seconds black screen, then my mail screen.

    Here’s my complete source for the entire test project;

    SplashtestActivity.java

    package com.android.splashtest;
    import android.app.Activity;
    import android.app.Dialog;
    import android.os.Bundle;
    import android.os.Handler;
    public class SplashtestActivity extends Activity {
    protected Dialog mSplashDialog;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MyStateSaver data = (MyStateSaver) getLastNonConfigurationInstance();
    if (data != null) {
    // Show splash screen if still loading
    if (data.showSplashScreen) {
    showSplashScreen();
    }
    setContentView(R.layout.main);
    // Rebuild your UI with your saved state here
    } else {
    showSplashScreen();
    setContentView(R.layout.main);
    // Do your heavy loading here
    try {
    Thread.sleep(5000);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
    MyStateSaver data = new MyStateSaver();
    // Save your important data here
    if (mSplashDialog != null) {
    data.showSplashScreen = true;
    removeSplashScreen();
    }
    return data;
    }
    /**
    * Removes the Dialog that displays the splash screen
    */
    protected void removeSplashScreen() {
    if (mSplashDialog != null) {
    mSplashDialog.dismiss();
    mSplashDialog = null;
    }
    }

    /**
    * Shows the splash screen over the full Activity
    */
    protected void showSplashScreen() {
    mSplashDialog = new Dialog(this, R.style.SplashScreen);
    mSplashDialog.setContentView(R.layout.splashlayout);
    mSplashDialog.setCancelable(false);
    mSplashDialog.show();

    // Set Runnable to remove splash screen just in case
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
    @Override
    public void run() {
    removeSplashScreen();
    }
    }, 3000);
    }

    /**
    * Simple class for storing important data across config changes
    */
    private class MyStateSaver {
    public boolean showSplashScreen = false;
    // Your other important fields here
    }

    main.xml

    splashlayout.xml

    string.xml

    Hello World, SplashtestActivity!
    Splashtest
    SPLASH SPLASH SPLASH

    styles.xml

    0dp
    @android:color/black
    @null

    AndroidManifest.xml

  10. Dennis says:

    The XML files don’t display correctly… Here’s the entire project in a zip file; http://dl.dropbox.com/u/35287699/splashtest.zip

    • Try removing the Thread.sleep() call.

      • Hani says:

        I have the same problem

        In Ian’s example he is just pointing out the issue with the Thread,sleep()

        I am making a call to a web service and also don’t see the splash page. If I remove the call to the web service then I get the splash page for 3 seconds before it disappears and shows the main content

        I also tried using a new handler to process the web call but that didn’t help

  11. Stephen says:

    It works for me. Thank you again.

  12. Pavel says:

    Hi Ian, i have googled your post as the most relevant to what i need to achieve (an iPhone-like splash on app startup). Your method somehow does not display anything unless the explicit removeSplashScreen() is left out, thus only the emergency delayed Runnable is responsible for removal. In that case, the splash screen is visible for a split second. I would guess (runnable_delay – startup_time). Complete black up to that point, regardless of what the style and layout says. Yes my startup code is fast but i need the splash anyway for the “iPhone-like-ness”. I was about to conclude that the app just is not capable of displaying ANYTHING yet. But then i found this pretty hack and it shows splash image immediately. Is your approach expected to do the same (in scope of displaying the very first activity) ?
    My initial activity goes simply like this (no threads etc.) :

    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    showSplashScreen();
    setContentView(R.layout.main);
    // ... init code ...
    removeSplashScreen(); // remove to see the splash for a moment
    }

    Thanks in advance.

    • Try removing your code at “// … init code …” to see if the splash screen displays. If it does, your init code is probably locking up the UI thread with work, so it should be moved to a background Thread such as with AsyncTask.

  13. Pingback: Good Articles About Android Splash Screens « More Is Not Always Better

  14. The Zero says:

    Here,
    I found a little easy way to obtained splash screen type functionality in android.

    http://mobituts.blogspot.com/2011/10/example-of-splash-screen-in-android.html

    • That example uses an artificial Activity to delay loading the actual Activity; I recommend against that method of generating a splash screen because it delays the application to create a splash screen that does nothing beneficial.

  15. Koen Mulder says:

    Thanks Ian, this was just what I needed! :)

  16. Mark says:

    Ha! Came looking for good ways to do a splash screen, and ended up being convinced we’d be better off without one. Need to look for less intrusive ways of branding :)

  17. Indira says:

    I’ve been googling about splash screen for some time and this is just what I need.. It really is a very good code. It really fits the purpose.

  18. Tos says:

    Hello,
    I did some experimenting with this code. However, when I launch my app, I see a black screen for 3 seconds (with the app title bar). Only then the splashscreen shows… when it is not needed since the interface is ready to be displayed.
    All the delay takes place between the lauch and the call to super.onCreate(savedInstanceState);
    Does this mean that there is nothng I can do apart from creating a splash activity ? This would do the job by filling the screen immediately but it is more complex to write.

    Thanks for reading,
    Tos

    • If your app is not displaying any UI for that long of a period of time, it most likely means that your main Thread is being kept busy by something. I’d recommend enabling StrictMode to see if that reveals anything obvious; otherwise, add some break points to figure out what’s keeping it so busy.

      • Tos says:

        I know the problem (parsing a large XML file with 15 k nodes). Since it feeds a ListView adapter it could be done on a background thread but I want to move on.. So eventually I created a Splash Activity using this : http://horribile.blogspot.com/2011/10/animated-splash.html
        The code is not totally kosher but it works fine for my purposes. For the next app, I’ll think about all this beforehand. Thanks !

  19. Betty says:

    What should we use for a splashScreen in this case:

    It takes 0.01 secs for our app to load.
    We’d still like to display a splashscreen for 1-2 secs.

    Then this “just wait for your app to load” method doesn’t work.

    • In that case, I would not have any splash screen. Your users open the app wanting to use it and you are instead preventing them from using it for 1-2 seconds. If you want to create an artificial delay like that, you can still use the above code, but you would call the postDelayed method of your handler in the showSplashScreen method with the artificial delay (1000-2000ms for 1-2 seconds).

  20. Heh, I think I may have an idea what app you’re working on that has a splashscreen.

  21. Sjoerd says:

    Hi,

    I’m using your code and it works like a charm, i’m now trying to make an transition animation (fade-out) to the main screen. any idea how i can add that? the way’s I’ve tried are not working so far.

    thnx

  22. Christian Donner says:

    I agree with you in general, but …
    Arguably, a splash screen is preferred for apps that use the license service , even though it does nothing but wait for the license response. If access is denied, I want to be able to exit out before I show the main activity to the user.

  23. Prasanna Perera says:

    Hello Ian,

    Good post. Thanks.

    I find that although I have ‘showSplash()’ before ‘setContentView(R.layout.main)’ in the onCreate method, my main content is shown for a brief second before the splash screen is shown. Is there a way to get the main content not show up at all until the splash screen goes away?

    Thanks,
    Prasanna

    • You can delay your setContentView call until later in your code, either after you get data back that will be included in the display or to just before dismissing the dialog. Basically, it could be this process: display splash screen, load/process raw data, load main layout (under the dialog), populate the main layout, dismiss the dialog.

  24. yous says:

    first of all , thanks for very good tutorial.
    I succeeded to run the splash screen and all OK, but what I tried is a static splash.s : 2 images on the screen.
    in my code I want these 2 images to be displayed with animation , and for that I need to write a code in the your example , I tested my little animation code alone and it works 100% (animate with alpha and rotations). ex:

    ImageView mainIv=(ImageView)findViewById(R.id.mainIv); //placed in splash.xml of course
    Animation an1=AnimationUtils.loadAnimation(this, R.anim.zoom);
    mainIv.startAnimation(an1);

    my Q is , where can I post this simple code to run the animation ?
    may you please mention 2 lines in your example to put it between ?

    regards

    • You should start animations after onCreate has finished. It would probably make the most sense to put them in onResume and stop them in onPause (checking to see if your splash screen is visible in both cases).

  25. Avinash says:

    Hi Gr8 work .. But i need to add image to splash screen .. can u help me??? pls mail me thnks in advance.

  26. Shannan says:

    Hi Ian,
    Thanks for the great example on setting up splash screens correctly!

    I’m interested in learning more about using a splash screen, with an AsyncTask and the onPostExecute method. Would you be able to provide a simple example of how you would go about running some heavy code, while showing the splash screen, and how you would remove the splash screen in the onPostExecute method once the heavier code has completed?

    • Hi Shannan, sorry I didn’t see this sooner. The onPostExecute method can directly trigger the removeSplashScreen method, since it operates on the UI thread. In the case of using an AsyncTask, you don’t need to have a special timer to remove the splash screen “just in case” as long as you handle the cancels/failures. One thing to keep in mind is that AsyncTasks execute on a single Thread by default in Honeycomb (so, if you’re running more than one AsyncTask, they will execute serially).

  27. Laurent says:

    Hi,

    Another way for splash screen with fragment
    Rotation works : initialization thread is not restarting.

    http://www.michenux.net/splashscreen-android-221.html

    • Yes, that’s correct. A Fragment is probably the best way to do it now (assuming your first Activity isn’t a MapActivity or otherwise prevents the use of Fragments). At some point I’d like to write an updated version of this article; just need to find the time.

  28. Harsh says:

    Ian,

    I want to show a splash screen between my first and second activity both making use of AsyncTask. First being a simple login screen retrieving data for the whole app and second loads the activity specific data. Currently, both the activities have their own ProgressDialogs which is quite naive but they were developed individually and initially I wasn’t planning to put them one after the other.

    Now, in order to place a splash screen in between them do I have to transfer all the loading process in a single activity? Which activity should contain the code for the splash screen?

    • It depends on the user interaction required. For example, if the first Activity displays a simple login form and does not need to retrieve any data before being displayed, then it would make sense to immediately show it. When the user enters credentials, stay on that screen while they are verified (assuming they have to be verified remotely). That allows you to easily display the form again in case of an incorrect password or similar.

      Once the credentials have been validated, then you can go to the second Activity. If it requires remote data before anything can be done, then you can display a splash screen or other loading indicator. If some things can be done without waiting for external sources, then the UI needs to reflect that. For example, a user might be able to jump from there to a search page before anything loads, but the main content might be grayed out while it is loaded in.

  29. Billy says:

    Hi am getting an error on this line

    mSplashDialog.setContentView(R.layout.SplashScreen);

    any suggestions?

    • Billy says:

      Here is the error message I get

      ‘SplashScreen cannot be resolved or is not a field’

      • My suspicion is that the android.R class is being included instead of your app’s generated R class. Check your import statements at the top to make sure it has something like “import com.example.myapp.R”

        • Billy says:

          Thank you for the reply, I will check this out when I get home later.

        • Billy says:

          Hi I tried that but no joy, the word ‘splashscreen’ is highlighted on red, and when I hover over it ther error is below.

          “…
          package com.example.splashscreen;

          import android.view.View;
          public final class R {

          public static final class layout {
          public static final int activity_main=0x7f030000;
          public static View splashscreen;
          }
          …”

  30. Billy says:

    New error on same area is

    “splashscreen cannot be resolved or is not a field”

    on the same line of code
    “mSplashDialog.setContentView(R.layout.splashscreen);”

    and this is how I have imported R
    “import com.example.splashscreen.R;”

    Some notes:
    Ive not done any work on layout folder :S

    cheers for all your help

  31. Krashnet says:

    Hi dude, (sry for may bad english) thx very much for your tutorial…
    It works like a charm!

    TROUBLE:
    I need to charge 2 splash screens (as a cinema movie)
    Example:
    Logo.xml >
    MovieCover.xml >
    Main.xml (with te rest of the contents and screens).

    QUESTION: How can i do this?
    To show the MovieCover.xml between Logo and Main?

    I tryed many times to create a second xml and modify splashscreenactivity to do it but i can’t find a right way.

    Can you help me please?
    Thx in advance!
    Krash

  32. Balk79 says:

    Hi,

    I’m trying to figure out how your code is working. I need to create / read properties from SQLite table “Settings”, and when this is read, according to results I’m loading one of 5 possible screens.

    So If firstRun is True -> Disclamer
    If MediaAcceptance is True -> MediaAcceptance
    If Yes was clicked on Media acceptance ->Settings
    if no was clicked on Media acceptance -> PreSettings
    if PreSettings is true -> Settings
    if Settings is true -> Going finaly to MyApp

    So on the first run I’m going throug disclamer and some presettings that should save certain fields in database, and on “re-run” I should load myApp directly every following time.

    Now, what I do not understand, Should I create Asynch task in your “onCreate” else statement, and set the DB, and load properties in order to make it right?
    } else {
    showSplashScreen();
    setContentView(R.layout.yourmainlayout);
    // Do your heavy loading here on a background thread
    Async Here?
    }

    At the moment I’m using SharedPrefs, but it’s needed to save everything into DB, so I must modify my code.

    Tnx.

    • Yes, that’s where I would put the AsyncTask. I’d also make sure each of those screens is actually handled by a Fragment so that whichever is needed can easily be shown as soon as possible.

  33. JC says:

    is better than the others I’ve seen but not perfect by any means.
    This is what happens:
    -calls the dialog
    -load the rest of “onCreate ()”
    -shows the dialog
    this in android 2.3 at least.

Comments are closed.