'GameOver dialog in Android Game
This method must display results when the game ends, but in line final DialogFragment gameResult = new DialogFragment() {...} I have an error "Fragments should be static such that they can be re-instantiated by the system, and anonymous classes are not static". But when I'm trying to change to static class, I have no-static method newGame(), which I can't change to static because of inner methods. So how can I fix the whole problem?
// display an AlertDialog when the game ends
private void showGameOverDialog(final int messageId) {
// DialogFragment to display game stats and start new game
final DialogFragment gameResult =
new DialogFragment() { //error on this line
// create dialog displaying String resource for messageId
@Override
public Dialog onCreateDialog(Bundle bundle) {
// display number of shots fired and total time elapsed
AlertDialog.Builder builder =
new AlertDialog.Builder(getActivity());
builder.setTitle(getResources().getString(messageId));
builder.setMessage(getResources().getString(
R.string.results_format, shotsFired, totalElapsedTime));
builder.setPositiveButton(R.string.reset_game,
new DialogInterface.OnClickListener() {
// called when "Reset Game" Button is pressed
@Override
public void onClick(DialogInterface dialog,
int which) {
dialogIsDisplayed = false;
newGame(); // set up and start a new game
}
});
return builder.create(); // return the AlertDialog
}
};
// in GUI thread, use FragmentManager to display the DialogFragment
activity.runOnUiThread(
new Runnable() {
public void run() {
showSystemBars();
dialogIsDisplayed = true;
gameResult.setCancelable(false); // modal dialog
gameResult.show(activity.getFragmentManager(), "results");
}
});
}
// reset all the screen elements and start a new game
public void newGame() {
// construct a new Cannon
cannon = new Cannon(this,
(int) (CANNON_BASE_RADIUS_PERCENT * screenHeight),
(int) (CANNON_BARREL_LENGTH_PERCENT * screenWidth),
(int) (CANNON_BARREL_WIDTH_PERCENT * screenHeight));
Random random = new Random(); // for determining random velocities
targets = new ArrayList<>(); // construct a new Target list
/// initialize targetX for the first Target from the left
int targetX = (int) (TARGET_FIRST_X_PERCENT * screenWidth);
// calculate Y coordinate of Targets
int targetY = (int) ((0.5 - TARGET_LENGTH_PERCENT / 2) *
screenHeight);
// add TARGET_PIECES Targets to the Target list
for (int n = 0; n < TARGET_PIECES; n++) {
// determine a random velocity between min and max values
// for Target n
double velocity = screenHeight * (random.nextDouble() *
(TARGET_MAX_SPEED_PERCENT - TARGET_MIN_SPEED_PERCENT) +
TARGET_MIN_SPEED_PERCENT);
// alternate Target colors between dark and light
int color = (n % 2 == 0) ?
getResources().getColor(R.color.dark,
getContext().getTheme()) :
getResources().getColor(R.color.light,
getContext().getTheme());
velocity *= -1; // reverse the initial velocity for next Target
// create and add a new Target to the Target list
targets.add(new Target(this, color, HIT_REWARD, targetX, targetY,
(int) (TARGET_WIDTH_PERCENT * screenWidth),
(int) (TARGET_LENGTH_PERCENT * screenHeight),
(int) velocity));
// increase the x coordinate to position the next Target more
// to the right
targetX += (TARGET_WIDTH_PERCENT + TARGET_SPACING_PERCENT) *
screenWidth;
}
// create a new Blocker
blocker = new Blocker(this, Color.BLACK, MISS_PENALTY,
(int) (BLOCKER_X_PERCENT * screenWidth),
(int) ((0.5 - BLOCKER_LENGTH_PERCENT / 2) * screenHeight),
(int) (BLOCKER_WIDTH_PERCENT * screenWidth),
(int) (BLOCKER_LENGTH_PERCENT * screenHeight),
(float) (BLOCKER_SPEED_PERCENT * screenHeight));
timeLeft = 10; // start the countdown at 10 seconds
shotsFired = 0; // set the initial number of shots fired
totalElapsedTime = 0.0; // set the time elapsed to zero
if (gameOver) { // start a new game after the last game ended
gameOver = false; // the game is not over
cannonThread = new CannonThread(getHolder()); // create thread
cannonThread.start(); // start the game loop thread
}
hideSystemBars();
}
Solution 1:[1]
You need to pass an instance of the class containing newGame() to your static fragment (you could also use a top level class instead of the static inner class):
public class C {
private void showGameOverDialog(final int messageId) {
gameResult = new GameResultFragment(this);
//...
}
public void newGame() {
//...
}
static class GameResultFragment extends DialogFragment {
private C newGameCreator;
public GameResultFragment(C c) {
newGameCreator = c;
}
public Dialog onCreateDialog(Bundle bundle) {
//...
builder.setPositiveButton(R.string.reset_game,
new DialogInterface.OnClickListener() {
// called when "Reset Game" Button is pressed
@Override
public void onClick(DialogInterface dialog,
int which) {
dialogIsDisplayed = false;
/// change v
newGameCreator.newGame();
/// change ^
}
});
return builder.create(); // return the AlertDialog
}
}
}
Be careful though with keeping activity references in classes that are not affected by android configuration changes and background task cleanup (C in this case) because android is very keen on recreating (destroying) the ui (activities) at every opportunity and you might end up with a reference to a destroyed activity and the exceptions when you try to use it. If you reassign the 'activity' field each time the activity is started/resumed you should be safe.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Crispert |