views:

419

answers:

2

I'm trying to find a way to properly handle setting up an activity where its orientation is determined from data in the intent that launched it. This is for a game where the user can choose levels, some of which are int portrait orientation and some are landscape orientation. The problem I'm facing is that setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) doesn't take effect until the activity is fully loaded. This is a problem for me because I do some loading and image processing during startup, which I'd like to only have to do once.

Currently, if the user chose a landscape level:

  • the activity starts onCreate(), defaulting to portrait
  • discovers from analysing its launching Intent that it should be in landscape orientation
  • continues regardless all the way to onResume(), loading information and performing other setup tasks
  • at this point setRequestedOrientation kicks in so the application runs through onPause() to onDestroy()
  • it then again starts up from onCreate() and runs to onResume() repeating the setup from earlier

Is there a way to avoid that and have it not perform the loading twice? For example, ideally, the activity would know before even onCreate was called whether it should be landscape or portrait depending on some property of the launching intent, but unless I've missed something that isn't possible. I've managed to hack together a way to avoid repeating the loading by checking a boolean before the time-consuming loading steps, but that doesn't seem like the right way of doing it. I imagine I could override onSaveInstanceState, but that would require a lot of additional coding. Is there a simple way to do this?

Thanks!


Solution:

As per Daniel's answer, this was actually quite easy to fix. I just needed to make a few small changes. In my 'menu' Activity, where the player would choose which level to play, I just had to add an if/else check to choose which class would be started by my Intent. This was done with a simple int representing portrait or landscape, determined when the player selected a level. I then created a second class extending my 'GameLogic' class; this is the class which contained most of the code for the game itself, rather than the menus, instructions, etc.

public class GameLandscape extends GameLogic{
}

Literally that simple and completely empty. That way it inherited all the code from my previous activity where I had already coded it to handle things differently depending on the orientation. Lastly I just had to add a line to the manifest stating that GameLandscape would always run in landscape, and GameLogic would always run in portrait.

So a simple problem indeed.

+4  A: 

You could make two Activities - one for portrait levels, the other for landscape levels - and then set the Activity's orientation in AndroidManifest.xml, using the android:screenOrientation attribute. You won't even have to duplicate code if you use inheritance; use your current Activity as the base activity, and just create the landscape/portrait Activities as subclasses of that Activity.

I think a better solution would be for the Intent to open the correct Activity of these two, though if you must have everything be routed via Intent extra analysis, you could forward all levels to a third Activity that does nothing more than analyse the Intent and then forward it to the proper Activity.

Daniel Lew
That's a good idea, thanks. I'll give that a go. (I'm not sure how I'd need a third activity though - yes, I do need to process the Intent to get other information stored in extras, but that code already exists in my Activity anyway. If you meant that I could need a 3rd Activity to choose which one to send it to, then I could just do that when storing the orientation in the extras to begin with. Where am I misunderstanding that part of your answer? :P)
Steve H
Well, you said how you use the Intent to determine whether to be in landscape or portrait mode. If you really need to do that, you could use a 3rd Activity to analyze it then forward it. But like I said, the best solution would be for the Intent to just call the correct orientation in the first place. (Sorry if my answer is a little confusing).
Daniel Lew
This worked a treat and was dead simple to implement. Details added below my question for anyone else who is having the same problem.
Steve H
+2  A: 

You could also override onRetainNonConfigurationInstance(). This lets you temporarily store one item that you can retrieve by calling getLastNonConfigurationInstance(). That way you can load all of the stuff that you need and in your onRetainNonConfigurationInstance() method you can save it all into a data structure and return it. The in your onCreate() you can call getLastNonConfigurationInstance() and if that returns null load, load all of your stuff, if it return something, then you have it all loaded. Here's a quick example:

public class MyActivity extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        DataStructure myData = (DataStructure)getLastNonConfigurationInstance();
        if(myData == null)
        {
            // Load everything in
        }
        else
        {
            // Unpack myData
        }
    }

    @Override
    public Object onRetainNonConfigurationInstance()
    {
        DataStructure myData = new DataStructure();
        // Put everything in to myData
        return myData;
    }
}
CaseyB
Ah yes, I had forgotten about the onRetainNonConfigurationInstance, but this solution seems broadly similar to overriding onSaveInstanceState. Both would require a bit of work to make sure I properly saved everything. Daniel's solution above is just so much easier to do, which is why I've picked it.
Steve H
This is the correct way to do this kind of thing when you need to do preprocessing once.
MrSnowflake