Code for detecting when you leave an Android app

Further to Detecting whether an Android app is stopping (or starting), I implemented code to decide when you are leaving or entering my game Rabbit Escape.

The relevant class is called Lifecycle2SoundEvents. (Yes, it’s a terrible name. Yes, I spent a long time trying to name it, and this is the best I came up with.)

And the tests, which are in TestLifecycle2SoundEvents, look like this:

@Test
public void Press_the_home_button_api10_causes_pause()
{
    Tester t = new Tester( activity1 );

    t.in.onSaveInstanceState( activity1 );
    t.in.onPause( activity1 );
    t.in.onStop( activity1 );

    // When we press home, we must at least pause (really we stop)
    t.assertPaused();
}

which I was reasonably pleased with, because they match my original blog post Order of Android Activity lifecycle events fairly well, without too much noise.

Detecting whether an Android app is stopping (or starting)

I am writing an Android app (called Rabbit Escape), and I want it to start playing music when the user enters the app, and stop when the user leaves.

Not as easy as it sounds because Android largely doesn’t think in apps, but Activities.

Update: real-life code for this is here: Code for detecting when you leave an Android app.

In my previous post Order of Android Activity lifecycle events I tracked the methods that get called on activities on my two test devices when the user does various actions. There was some variation between devices, but we can determine some useful rules.

First, let’s enumerate what we need to detect.

The user leaves by:

  • pressing “home” at any time
  • pressing the power button when the app is running
  • pressing “back” when in the first activity
  • launching an external activity (e.g. web browser)

The user enters by:

  • starting the app (e.g. from the home page, or the “running apps” panel)
  • pressing the power button when the app has been suspended
  • pressing “back” when in an external activity launched by us

From the previous post we can work out these rules:

  • When the user is entering, onResume is always called (on the activity that will be current)
  • When the user is leaving, onStop is always called (on the current activity), except when pressing the power button (to turn off) where you may only see an onPause call.
  • When the user is moving between activities, onResume is always called on the new activity, and onStop is always called on the old one. The onResume call is always before onStop

Thus, if we are OK with leaving ourselves running when the power button is pressed, we can detect leaving and entering the app using the code below.

If we need to stop something when the power button is pressed too, it seems we must be prepared to stop it when we receive onPause, and immediately restart it if we receive onResume, hoping that doesn’t cause a problem (e.g. a break in the music).

// All activities have these two methods:
@Override
public void onResume()
{
    super.onResume();
    LeavingOrEntering.activityResumed( this );
}

@Override
public void onStop()
{
    super.onStop();
    LeavingOrEntering.activityStopped( this );
}

// And we detect leaving and entering like this:
class LeavingOrEntering
{
    private static Activity currentActivity = null;

    public static void activityResumed( Activity activity )
    {
        if ( currentActivity == null )
        {
            // We were resumed and no-one else was running.
            notifyEntering() // Start the music!
        }
        currentActivity = activity;
    }

    public static void activityStopped( Activity activity )
    {
        assert currentActivity != null;

        if ( currentActivity == activity )  
        {
            // We were stopped and no-one else has been started.
            notifyLeaving(); // Stop the music!
        }
        currentActivity == null;
    }
}

Rabbit Escape 0.3.1 – now with zoom!

I’ve just release the latest version of Rabbit Escape, which makes things look a lot nicer because you can zoom in, getting you much closer to your rabbits:

rabbitescape-android-zoomed

There are still 60 levels of Lemmings and Pingus -like gameplay, all downloadable for free artificialworlds.net/rabbit-escape/.

I’ve also improved performance significantly, so you should notice things get smoother on older devices.

All those zoomed images increase the download size to 9MB, which is a pity, but that’s still pretty small.

Java game programming: image rendering hints make no difference to rendering time

I am writing an Open Source/Free Software Java desktop game (Rabbit Escape) and am experimenting with allowing you to zoom in so that the images being rendered are fairly big, and I’m seeing some slow-down.

[Note: Rabbit Escape is also available on Android, where it appears to have no problems with rendering speed…]

To speed it up, I have been experimenting with passing various values to Graphics2D‘s setRenderingHint method.

My conclusion is that on my platform (OpenJDK Java 7 on Linux) it makes no difference whatsoever. Please leave a comment if I’m doing it wrong.

I am timing how long each frame takes to render, and comparing the time when I insert this code before my rendering code:

// As slow and high-quality as possible, please!
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
g.setRenderingHint( RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY );
g.setRenderingHint( RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY );
g.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY );

with inserting this before my rendering code:

// As fast and low-quality as possible, please!
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
g.setRenderingHint( RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED );
g.setRenderingHint( RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED );
g.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED );

[Documentation, such as it is, is here: RenderingHints.]

I see no appreciable difference in rendering time or image quality between these two setups, or when I leave out the calls to setRenderingHint completely.

Platform details:

$ java -version
java version "1.7.0_75"
OpenJDK Runtime Environment (IcedTea 2.5.4) (7u75-2.5.4-1~trusty1)
OpenJDK 64-Bit Server VM (build 24.75-b04, mixed mode)