1

Yes, i have read many other posts, but i am unable to follow along because i have lots of variables, Not just One or Two.

I am making an app(TIC TAC TOE) for first time with landscape support. I am losing data on screen rotation.

package com.netlify.krupesh.tictactoe;

import android.graphics.Typeface;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    // 0 for zero and 1 for X
    // 2 for empty
    boolean gameActive = true;
    int[] gameState = {2,2,2,2,2,2,2,2,2};
    int[][] winningPositions = {{0,1,2}, {3,4,5}, {6,7,8}, {0,3,6}, {1,4,7}, {2,5,8}, {0,4,8}, {2,4,6}};

    int activePlayer = 0;
    int[] playerScores = {0,0};

    // Show Symbol on Tap
    public void showSymbol(View view){
        // Set Player Scores
        TextView player1 = (TextView) findViewById(R.id.p1Score);
        TextView player2 = (TextView) findViewById(R.id.p2Score);


        player1.setText(playerScores[0]+"");
        player2.setText(playerScores[1]+"");

        // Get Symbol Info
        ImageView symbol = (ImageView) view;
        int tappedSymbol = Integer.parseInt(symbol.getTag().toString());

        // Update Game state Array
        if(gameState[tappedSymbol]==2 && gameActive) {
            gameState[tappedSymbol] = activePlayer;

            // Show Symbol with Animation
            symbol.setAlpha(0f);
            if (activePlayer == 0) {
                symbol.setImageResource(R.drawable.zero);
                activePlayer = 1;
                showCurrentPlayer(2);

            } else {
                symbol.setImageResource(R.drawable.cross);
                activePlayer = 0;
                showCurrentPlayer(1);
            }
            symbol.animate().alpha(1).setDuration(400);

            checkDraw(gameState);

            for (int[] winningPosition : winningPositions) {
                if (gameState[winningPosition[0]] == gameState[winningPosition[1]] && gameState[winningPosition[1]] == gameState[winningPosition[2]] && gameState[winningPosition[0]] != 2) {
                    showCurrentPlayer(0);
                    // Pause The Game
                    gameActive = false;

                    // Won the Game
                    String winningPlayer ;
                    if (gameState[winningPosition[0]] == 0) winningPlayer = "Player 1";
                    else winningPlayer = "Player 2";
                    Toast.makeText(this, winningPlayer + " won!", Toast.LENGTH_SHORT).show();

                    // Update Scores
                    playerScores[gameState[winningPosition[0]]]++;
                    player1.setText(playerScores[0] + "");
                    player2.setText(playerScores[1] + "");
                }
            }
        }
    }


    public void resetBoard(View view){
        android.support.v7.widget.GridLayout board = (android.support.v7.widget.GridLayout)findViewById(R.id.gridLayout);
        for(int i=0; i<board.getChildCount(); i++) {
            ImageView symbol = (ImageView) board.getChildAt(i);
            symbol.setImageDrawable(null);
        }
        for(int i=0; i<gameState.length; i++ ){
            gameState[i] = 2;
        }
        gameActive = true;
        activePlayer = 0;
        showCurrentPlayer(1);
    }

    public void checkDraw(int[] gamestate){
        for(int i =0; i<gamestate.length; i++){
            if(gamestate[i]==2){
                return;
            }
        }
        showCurrentPlayer(0);
        Toast.makeText(this, "Match Draw!", Toast.LENGTH_SHORT).show();
    }

    public void resetAll(View view){
        resetBoard(view);
        playerScores[0]=0; playerScores[1]=0;
        TextView player1 = (TextView) findViewById(R.id.p1Score);
        TextView player2 = (TextView) findViewById(R.id.p2Score);
        player1.setText(playerScores[0] + "");
        player2.setText(playerScores[1] + "");
        showCurrentPlayer(1);
    }

    public void showCurrentPlayer(int i){
        TextView player1Heading = (TextView) findViewById(R.id.subheading1);
        TextView player2Heading = (TextView) findViewById(R.id.subheading2);
        if(i==1){
            player1Heading.setTextColor(getResources().getColor(R.color.colorPlayer1));
            player1Heading.setTypeface(null, Typeface.BOLD);
            player2Heading.setTextColor(getResources().getColor(R.color.colorHeading));
            player2Heading.setTypeface(null, Typeface.NORMAL);
        }
        if(i==2){
            player2Heading.setTextColor(getResources().getColor(R.color.colorPlayer2));
            player2Heading.setTypeface(null, Typeface.BOLD);
            player1Heading.setTextColor(getResources().getColor(R.color.colorHeading));
            player1Heading.setTypeface(null, Typeface.NORMAL);
        }
        if(i==0){
            player1Heading.setTextColor(getResources().getColor(R.color.colorHeading));
            player1Heading.setTypeface(null, Typeface.NORMAL);
            player2Heading.setTextColor(getResources().getColor(R.color.colorHeading));
            player2Heading.setTypeface(null, Typeface.NORMAL);
        }
    }



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

        // ===================== Hide Status Bar ========================== //
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        // ================================================================ //

        setContentView(R.layout.activity_main);
        showCurrentPlayer(1);
    }
}

See, there are so many things.. For all ImageViews i need to save who have their images set. Now how do i solve this problem of rotation??

Solution with Code Snippet to be added is what will prove helpful the most, New to Android Development

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
krupesh Anadkat
  • 1,932
  • 1
  • 20
  • 31
  • 3
    [Use `ViewModel`](https://developer.android.com/jetpack/arch/viewmodel). Or, use the saved instance state `Bundle`. – CommonsWare Jan 18 '19 at 17:01
  • that is like Greek and Latin for me, could you share a code Snippet, PLeaseeee.@CommonsWare – krupesh Anadkat Jan 18 '19 at 17:02
  • 1
    I recommend that you take the time to actually learn the material, rather than just relying on random code snippets. Read a book that covers these topics. Or, take a course that covers these topics (live, Udacity videos, etc.). – CommonsWare Jan 18 '19 at 17:08
  • yeah sure. I did 2 courses from udacity for android beginners and i could create a beautiful UI Tic Tac Toe, fully functioning. Just Few Polishes to launch in Playstore.. i can always keep learning.. – krupesh Anadkat Jan 18 '19 at 17:10
  • turning off screen rotation through manifest will be last option for now if people didnt help. – krupesh Anadkat Jan 18 '19 at 17:12
  • 2
    Great! If that was the official Google course, it should cover either `ViewModel` or the saved instance state `Bundle`. If you are saying that those courses covered neither subject... that indicates those are bad courses. While `ViewModel` is relatively new, the saved instance state `Bundle` has been with us from the beginning. – CommonsWare Jan 18 '19 at 17:13
  • not helpful anymore. thanks for discussion though. – krupesh Anadkat Jan 18 '19 at 17:23
  • You may want to refer to: https://stackoverflow.com/questions/16769654/how-to-use-onsaveinstancestate-and-onrestoreinstancestate – Phantômaxx Jan 18 '19 at 17:25
  • ViewModel should be the best option – Max Pinto Jan 18 '19 at 18:05

1 Answers1

1

@krupesh Anadkat I get the frustration as a newbie but @CommonsWare is a seasoned developer who has been in the game for days.

Follow his advice and make sure you learn the fundamentals he outlined rather than blazing through or just rushing to build something for the sake of it.

However today is your lucky day so I'll spoil you with some code snippets (we millennial programmers like it easy-yes I said it!!!) read on youngling and learn.

The issue you are facing here is a device configuration change.

In your case a screen orientation change.

Every darn time a user rotates that screen the Android OS recreates your activity a new. The Android OS means no harm its simply trying to be efficient in that its checking if there are better resources for that new orientation and if so it can use those instead.

This is the source of your pain. Now lets crack on and help you out mate.

You can use the Activity's class methods to work your way out of this one. Before the almighty Android OS kills your Activity the method onSaveInstanceState() will be called in your Activity's lifecycle. In your class you override onSaveInstanceState() and save the data you want to the Bundle which onSaveInstanceState() takes as an argument.

Then in your Activity's onCreate() you check if savedInstanceState is not null if its not null you retrieve you data.

Beware though; its best to save primitive data types to the Bundle or objects that are serializable to avoid retrieving data that is stale i.e. out of date or not valid anymore.

See code snippet for my SaveDataAcrossScreenOrientation Activity below

package com.demo.android.savedataacrossscreenrotationdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class SaveDataAcrossScreenOrientation extends AppCompatActivity {

    // Key to be used for the key: value pair to be saved to the bundle
    private static final String KEY_GREETING_TEXT = "greeting_text";

    // The text currently displayed to the screen
    private String mCurrentDisplayedText;

    private TextView mGreetingTextView;
    private Button mSpanishButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Get references to the button and textview
        mGreetingTextView = (TextView) findViewById(R.id.greeting_text_view);
        mSpanishButton = (Button) findViewById(R.id.change_greeting_button);

        // If mCurrentDisplayedText is inside the bundle retrieve and display it on screen
        if(savedInstanceState != null) {
            mCurrentDisplayedText = savedInstanceState.getString(KEY_GREETING_TEXT, "");
            if (mCurrentDisplayedText != "") {
                mGreetingTextView.setText(mCurrentDisplayedText);
            }
        }

        // Set a listener on the spanish button
        mSpanishButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Change the english text to spanish when the button is clicked
                mGreetingTextView.setText(R.string.spanish_greeting);

                // Get the text currently shown in the text view
                mCurrentDisplayedText = (String) mGreetingTextView.getText(); // Calling getText() returns a CharSequence cast it to a string
            }
        });
    }

    // Override onSaveInstanceState(Bundle savedInstanceState) and save mCurrentDisplayedText to the bundle
    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putString(KEY_GREETING_TEXT, mCurrentDisplayedText);
    }

}

See video demo here

Have fun!

mtotowamkwe
  • 2,407
  • 2
  • 12
  • 19