• No results found

Coding the GameActivity

In document Hello, Android, 4th Edition (Page 72-76)

ticTacToev2/src/main/java/org/example/tictactoe/GameActivity.java package org.example.tictactoe; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log;

public class GameActivity extends Activity { @Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

setContentView(R.layout.activity_game); // Restore game here...

} }

The onCreate() method is called when the activity starts. It causes its view to be created from the layout/activity_game.xml XML definition we built earlier. Speaking of XML, every time you add a new activity to an Android program you have to update AndroidManifest.xml to reference it. Simply add these lines before the end of the application block:

ticTacToev2/src/main/AndroidManifest.xml

<activity

android:name="org.example.tictactoe.GameActivity"> </activity>

The value of the android:name attribute must match the package and class name of the activity in the Java code. If the package name is the same as the package specified in the manifest, you can leave out the package name. But don’t remove the dot (“.”) before the class name.

Continuing a Game

We need a way to continue a game that was already in progress. To do that, we need to add a few lines to the onCreate() method. We also need to declare some new members to GameActivity. Here’s the expanded definition:

ticTacToev2/src/main/java/org/example/tictactoe/GameActivity.java

public static final String KEY_RESTORE = "key_restore";

public static final String PREF_RESTORE = "pref_restore";

private GameFragment mGameFragment; @Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

setContentView(R.layout.activity_game); // Restore game here...

mGameFragment = (GameFragment) getFragmentManager() .findFragmentById(R.id.fragment_game);

boolean restore = getIntent().getBooleanExtra(KEY_RESTORE, false);

if (restore) {

String gameData = getPreferences(MODE_PRIVATE) .getString(PREF_RESTORE, null);

if (gameData != null) {

mGameFragment.putState(gameData); }

}

Log.d("UT3", "restore = " + restore); }

KEY_RESTORE is the name of the flag passed in to the new activity in order to cause the board to be restored from its frozen state. We call the getBooleanExtra() method on the Intent instance that started us to get the value of the flag. If it’s true, then we use the getPreferences() method to get a handle to the Android preferences manager for this activity, and then call getString() to get the value of the PREF_RESTORE item. Preferences are a great way to store small amounts of data persistently. For larger amounts of data, you should use the SQLite database (see Chapter 13, Putting SQL to Work, on page 183).

To talk to the game fragment inside the activity, we call getFragmentManager() to get a handle to the object that keeps track of all the fragments, and then call the findFragmentById() method to get a reference to the game fragment. This isn’t the only way to do it, or even necessarily the best way, but it’s practical and it works. If we were able to get the game state from the preferences, then we could call the fragment’s putState() method to change the game state.

When the GameActivity started, it read the state of the game from the prefer- ences. Now let’s look at how that was set.

Saving the Game

The behavior we want is this: no matter how the game was stopped, whether it was because we exited to the home screen, started another app, or just pressed the Back button, we want to be able to continue from that point. To do that, we need to save the game every time the activity goes out of the running state (see the lifecycle diagram on page 23).

In that diagram, you will see that the onPause() method is a good place to do the saving. So let’s create an onPause() method inside the GameActivity class to add that now (don’t forget the Ctrl+Alt+L shortcut to reformat the code to make it more readable):

ticTacToev2/src/main/java/org/example/tictactoe/GameActivity.java

@Override

protected void onPause() { super.onPause();

String gameData = mGameFragment.getState(); getPreferences(MODE_PRIVATE).edit()

.putString(PREF_RESTORE, gameData) .commit();

Log.d("UT3", "state = " + gameData); }

First, we call the onPause() method in the superclass, which is Activity.onPause(). You should always call the super’s method in any method that overrides a method in the superclass. For all the onXX functions that have something to do with initialization, in general you should call the super’s method at the very beginning of the method, but for the ones that are called at termination time, you should call it at the end. If you’re not sure, just call it at the beginning.

After that, we call the fragment’s getState() method to get the game data. Then we get a handle to the preferences store (getPreferences), create an editor for preferences (edit), save a string under the key PREF_RESTORE (putString), and finally save the changes back to the preferences store (commit). The Log.d() call writes a debugging message to the log.

Restarting the Game

Sometimes we may want to just wipe the slate clean and start over. That’s the purpose of the restartGame() method:

ticTacToev2/src/main/java/org/example/tictactoe/GameActivity.java

public void restartGame() { mGameFragment.restartGame(); }

It simply calls a method of the same name in the fragment class. We’ll look at that class in a moment.

Declaring a Winner

Once the winner has been decided we’ll need some way to announce that fact. The reportWinner() method takes care of that:

ticTacToev2/src/main/java/org/example/tictactoe/GameActivity.java

public void reportWinner(final Tile.Owner winner) {

AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(getString(R.string.declare_winner, winner)); builder.setCancelable(false);

builder.setPositiveButton(R.string.ok_label,

new DialogInterface.OnClickListener() { @Override

public void onClick(DialogInterface dialogInterface, int i) { finish();

} });

final Dialog dialog = builder.create(); dialog.show();

// Reset the board to the initial position mGameFragment.initGame();

}

This code uses the AlertDialog.Builder class to create a message box containing a single line of text and an OK button. When the user presses OK, the activity will finish—that is, the game screen will close and the user will be returned to the main menu.

In document Hello, Android, 4th Edition (Page 72-76)