Splash screens form a very common pattern in mobile development. As simple as showing the user a beautiful logo and maybe doing some background loading may seem, I’ve seen many more flawed implementations than correct ones so far.

The Worst Possible Way

If you want to display a static layout, wait a few moments and load something else, you might be tempted to do this:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.splash);

    Thread.sleep(SPLASH_DURATION_MS);

    startActivity(this, MainActivity.class);
    finish();
}

This is absolutely horrible. The Thread.sleep() call blocks the UI thread, rendering the application unresponsive and possibly causing a force-close. This is absolutely not the way to go about it.

The Very Bad Way

To avoid blocking, you might resort to firing a thread, sleeping there, and calling runOnUiThread() to start the next Activity. This would effectively address the issue with the previous implementation. There’s no need to fire another thread just to let time go by, however. We can do better.

The Still Bad Way

Using Android’s Handler, you can post an event to the main UI loop and schedule it to run after a delay.

private Handler mHandler = new Handler();
    
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.splash);
    
    mHandler.postDelayed(new Runnable() {
        public void run() {
            startActivity(new Intent(
                SplashActivity.this, MainActivity.class
            ));
            finish();
        }
    }, SPLASH_DURATION_MS);
}

Well, this is still bad, but for different reasons: even if the interface is responsive, and there’s nothing problematic going on in the code, you’re making the user wait for God knows how long on a splash screen that he might have seen a zillion times already. It’s a perfect recipe for turning “oh, cool design!” into “START already, dammit!”.

The Right Way ™

Using the Handler method described above, why don’t we let the user interrupt the wait by clicking on the splash screen? If he’s busy staring at our artwork, let him; if he’s impatient, he’ll try to click anywhere and manually skip the splash.

Let’s see the full code for that:

public class SplashActivity extends Activity {
    
    private static final int SPLASH_DURATION_MS = 2000;
    
    private Handler mHandler = new Handler();
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash);
        
        mHandler.postDelayed(mEndSplash, SPLASH_DURATION_MS);
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mEndSplash.run();
        return super.onTouchEvent(event);
    }
    
    private Runnable mEndSplash = new Runnable() {
        public void run() {
            if (!isFinishing()) {
                mHandler.removeCallbacks(this);

                startActivity(new Intent(
                    SplashActivity.this, MainActivity.class
                ));

                finish();
            }
        };
    };
}

Not so simple as Thread.sleep(), I admit, but correctly implemented and completely copy-pastable.

Advertisements