The Case of the Twin onSurfaceChanged() and the Split Action Bar
There's a funny little timing problem I ran into recently I'd like to share regarding window size and split action bars.
In an app I've got a loading screen that displays as we're making network requests. It's a cute SurfaceView
with some animation to keep users amused. I'd written most of the initialization of assets inside of onSurfaceChanged()
because I wanted to pre-scale everything to the exact size of the surface.
But a problem arose - for some reason onSurfaceChanged()
was being called twice (and only when in portrait, not in landscape). This was troublesome because it's somewhat a substantial method due to all the initialization. What was happening?
It turns out that the split action bar was the culprit. Here's how things went down:
-
In
onCreate()
, add theSurfaceView
to the view hierarchy. -
SurfaceView.onSurfaceChanged()
would be called. -
onCreateOptionsMenu()
would then be called. Since I hadsplitActionBarWhenNarrow set for the Activity, this would create the split action bar. -
Due to the split action bar, the window size would change.
SurfaceView.onSurfaceChanged()
would be called a second time.
The solution was to move the addition of the Fragment with the SurfaceView somewhere after onCreateOptionsMenu()
. I put it in onPostResume()
(but make sure to call it only once on initialization).
There is one alternative solution, which is to call invalidateOptionsMenu()
(or supportInvalidateOptionsMenu()
, if you're using the support library) during onCreate(). This will force onCreateOptionsMenu()
to be called early. I dislike this answer because it screws up the normal lifecycle for menu creation and can therefore readily cause confusing issues down the line.