Try PandaPow for Android
By date: Showing: April, 2010

RSS Feed

Skip this one

Translucent Full Screen problems

2010-04-29 13:50:19

Added toggling of full screen mode to my app today. It wasn't as simple as I had first thought. As always, there're several ways of doing it. The most basic way is to use one of the predefined themes. For instance add the following XML-property to your activity or app:

android:theme="@android:style/Theme.NoTitleBar.Fullscreen"

This will have the (dis)advantage of also removing the title bar. If you for some reason want full screen and title bar, you have to define your own theme. The android dev-site has more documentation on applying themes and styles . It also helps to have a look in the source files defining the themes. These are found in the sdk, for instance:

android-sdk-linux_86/platforms/android-2.1/data/res/values/themes.xml

But as I wanted to be able to toggle the fullscreen i needed to set it in code. So I proceeded to add the following function in my activity class:

void toggleFullscreen() {
    if (mFullscreen) {
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        mFullscreen=false;
    } else {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        mFullscreen=true;           
    }
}

to be called in order to toggles the screen mode. Happily thinking job done, I launched my app in the emulator only to find this:

Fullscreen mode
Normal mode

The fullscreen mode did indeed use the whole screen, but the statusbar was laid on top of it, instead of being hidden as I had expected.

The problem as it turns out was the the app had a translucent window background (it used the theme Theme.Translucent.NoTitleBar). This can be seen in the screen shot that the background isn't opaque, the home screen can be seen through it. The background color of the layout is set to c000.

To find out if this was a general problem, I also tried applying a theme that had the translucent and full screen parameters set. Turns out there is such a theme pre-defined:

android:theme="android:style/Theme.Translucent.NoTitleBar.Fullscreen"

This had the same effect as toggeling the fullscreen off, so it seems to be an inherent problem with mixing fullscreen mode and translucency. As a corollary this theme is only useful for an activity whuch is always on top of some other opaque fullscreen activity. That is, if an activity A in fullscreen mode, launches another activity B. The translucent fullscreen theme will work fine for the B, provided that A is not also translucent.

I was seeing this on android 2.1, but I've seen other posts that describes the same problem on 1.5 so I assume it is not version specific (at least not from 1.5 and forward).

So in conclusion it seems one must chose either fullscreen or translucency, can't have both. At least not for the main activity. Hmm, bummer.

Update: also tried setting the background drawable of the window to to make it transparent:

getWindow().setBackgroundDrawable(new ColorDrawable(0));

According to the documentation this should make the window transparent, but for me it had no effect whatsoever...

Skip this one

When to save the state?

2010-04-24 13:47:07

An Android Activity roughly corresponds to one specific user interface. At any given time, there is only one activity with which the user interacts. An application often has several activities, one which is the main activity and from which the others are launched. An activity should typically be able to save its state so that it can be paused and late resumed.

The android documentation gives a good overview of the activity life cycle. It is pretty much summed up by the below state diagram:

This state diagram seems pretty straight forward to understand, but there is an important detail which is easily overlooked and needs to be emphasized:

There is nothing that ensures that an instance of an activity is destroyed before another instance of the same activity is created.

In other words, there is no guarantee that onDestroy() is called on an old instance prior to onCreate() is called on a new instance.

Playing around with various android apps it is easy to be mislead into thinking that ther is such a guarantee. An activity is created when it is first launched. Then pauses when some other activity is launched on top of it, or the home button is used to switch to another app. When we return to a paused app, or back to a previous activity of the same app, it will be resumed as we left it. And when we exit an activity (e.g. pushing the back button) it will be destroyed.

In the app I was writing, I wanted the user to always return to the same state regardless of whether the app had been paused and resumed, or it had been closed using the back button and then relaunched. Looking at the activity life cycle diagram above, it then seemed appropriate to save the state in onDestroy() and restore it again in onCreate(). That however was a mistake.

While developing the app it worked fine to save the state in onDestroy(). But later when testing the app more thoroughly, the state wasn't always restored properly. It wasn't consistent either, sometimes it worked sometimes not depending on what other apps had been launched in between closing and relaunching. Using the debugger, the problem soon became clear: onDestroy() wasn't called when the app was closed, as expected. Instead a second instance of the main activity was created before the first instance could save its state.

Update: The behavior shown below is not normal to Android. It was in fact due to a static reference to the activity that wasn't cleared, and which prevented the system from destroying the activity (see here for more details ). Once this reference was cleared, the activity was indeed destroyed as expected. This doesn't mean one should count on it, however, so it is still "wrong" to save the state in onDestroy.

The problem can be illustrated by the following sequences. The first column is the expected sequence of events, the second column shows what actually happened.

Expected Actual
App launched
inst1.onCreate() loads initial state
App closed
inst1.onPause()
inst1.onDestroy() saves the state 1
App launched
inst2.onCreate() restores state 1
App closed
inst2.onPause()
inst2.onDestroy() saves state 2
App launched
inst3.onCreate() restores state 2
...
App launched
inst1.onCreate() loads initial state
App closed
inst1.onPause()
App launched
inst2.onCreate() no state to restore
inst1.onDestroy() saves the state 1
App closed
inst2.onPause()
App launched
inst3.onCreate() restores state 1
inst2.onDestroy() saves state 2
...

Looking at the two sequences, the it was quite clear how to fix it. The save of state should be done in onPause() instead. The following compares the sequence before and after the fix.

Before Fix After Fix
App launched
inst1.onCreate() loads initial state
App closed
inst1.onPause()
App launched
inst2.onCreate() no state to restore
inst1.onDestroy() saves the state 1
App closed
inst2.onPause()
App launched
inst3.onCreate() restores state 1
inst2.onDestroy() saves state 2
...
App launched
inst1.onCreate() loads initial state
App closed
inst1.onPause() saves the state 1
App launched
inst2.onCreate() restores state 1
inst1.onDestroy()
App closed
inst2.onPause() saves state 2
App launched
inst3.onCreate() restores state 2
inst2.onDestroy()
...

In hindsight this "fix" seems pretty obvious; all examples and tutorials suggest that saving of state should be done in onSaveInstanceState() which is always called immediately before onPause(). The reason this wasn't done in the first place was:

  1. The onSaveInstaceState() is meant for saving and restoring state in the case the instance is destroyed by the system, not if it is closed normally by the user.
  2. Saving state was potentially time consuming, so it seemed a bad idea to save state when just pausing. If the activity was later resumed without being destroyed, then the saved state would never be used.

For efficiency, it would of course be better if one could save the sate, only when it is necessary. But on the other hand, with the current solution, an application is forced to keep the state simple so as to not need time to save. That seems like a good direction to go in anyway.

Skip this one

onCreate()

2010-04-05 14:16:14

The idea first formed a bleak September day when a green little figure with a floppy head first entered my conscience. The future was here, in this retro looking little humanoid. Backed by massive resources and computing clouds of Google, this little guy was intent on creating a permanent home in the palm of every gadget geeks' hand. And after that, the rest would be sure to follow, sooner or later. Android was here to stay, and its eventual world domination was inevitable. The idea I had was simply to start building fun and beautiful android apps, no more nor less.

Getting a first app, [a simple entertainment app](Start/AmusingSnips), up and running was quite smooth thanks to all the docs tutorials at the [android developer site](http://developer.android.com/), and with some additional help from developers at [stack overflow](http://stackoverflow.com). Reading programming books is something I haven't done since I was in university. I learn by doing and Google:ing :)

The [ADT Plugin for Eclipse](http://developer.android.com/intl/fr/sdk/eclipse-adt.html) was a definite pleasant encounter. It made it fast and easy to create the first activities and services, and bundle it all into an app. Debugging wasn't exactly painless, but still better than a lot of other systems I've seen.

The first real difficulty was encountered just when we thought the app was ready for release. It all worked fine, first time it was launched. But after closing and relaunching, in which case it should load a saved state, the app sometimes failed. All very frustrating, since it seemed pretty much random, sometimes it worked sometimes not, and no one could understood why.

To be continued...

Page 1