'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