关闭片段后,在Android中恢复井字游戏

时间:2014-08-14 23:14:23

标签: android android-fragments

我正在通过创建测试项目来学习Android开发:Tic-tac-toe。我的Tic-tac-toe应用程序以主菜单活动开始,其中Button表示新游戏。单击New Game后,将启动包含Tic-Tac-Toe游戏(在GridLayout中)游戏的片段的活动。用户可以玩游戏,但当他们返回主菜单时,游戏状态不会被保存。

我想更改此设置,以便当用户返回主菜单时,他们会看到一个名为“Continue”的新Button(除了“新游戏”按钮)。一旦用户点击“继续”,他们之前玩的游戏就会继续。如果单击“新游戏”按钮,将像以前一样启动新游戏。

通过使用onSaveInstanceState方法和Bundle savedInstanceState,我能够在方向更改时保留游戏状态(通过从底层TicTacToe类保存数据)。我的代码显示了我是如何做到的。我想再次做类似的事情 - 我已经读过它,但我不太了解最好的开始方式。谁能告诉我正确的步骤?

请注意,我是以编程方式执行此操作(即设计xml文件之外的布局)!

我的MainMenu课程:

public class MainMenu extends ActionBarActivity {

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


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    public void startGame(View view) {
        Intent intent = new Intent(this,MainGame.class);
        startActivity(intent);
    }

}

使用相应的xml文件activity_main_game

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/new_game"
        android:onClick="startGame"

        />

</RelativeLayout>

现在我的MainGame.class看起来像这样:

public class MainGame extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_game);
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new BoardFragment()).commit();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_game, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    public static class BoardFragment extends Fragment {

        public TicTacToe t = new TicTacToe();  //A class I wrote that launches a simple TicTacToe game

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

            if (savedInstanceState != null) {
                t = new TicTacToe(savedInstanceState.getInt("TicTacToeData"),
                );
            }

    //Graphics stuff here: variable rootView which contains the TicTacToe grid is defined
    //and onClickListeners are added to the ImageViews in the GridLayout which makes corresponding
    //changes to t.

            return rootView;
        }

        @Override
        public void onSaveInstanceState(Bundle savedInstanceState) {
            savedInstanceState.putInt("TicTacToeData", t.getGameData());
        }

    }
}

感谢您的帮助。

4 个答案:

答案 0 :(得分:1)

您有两个选择

  1. SharedPreferences:您可以使用shaerdPreferences来存储游戏状态。它也会在重新启动应用程序后存储。
  2. 使用startActivityForResult()开始您的游戏活动,并在您的父活动上实施onActivityResult

答案 1 :(得分:1)

一种可能的解决方案是让你的MainGame活动在游戏结束时返回游戏状态。然后,您的MainMenu活动可以保存该值并使用它来启动处于相同状态的游戏。

对于初学者,您需要以能够返回值的方式启动游戏Activity:

public class MainMenu extends ActionBarActivity {

    ...

    public void startGame() {
        Intent intent = new Intent(this, MainGame.class);
        startActivityForResult(intent, 1);
    }
}

接下来,您需要确保您的电路板Fragment在关闭时返回正确的状态:

public class BoardFragment extends Fragment {

    ...

    @Override
    public void onPause() {
        Intent result = new Intent();
        result.putExtra("TicTacToeData", t.getGameData());
        getActivity().setResult(Activity.RESULT_OK, result);
    }
}

之后您将需要您的菜单活动记录结果:

public class MainMenu extends ActionBarActivity {
    private int mPreviousGameState;

    ...

    @Override
    protected void onActivityResult (int requestCode, int resultCode, Intent data) {
        if (requestCode == 1 && resultCode == Activity.RESULT_OK) {
            mPreviousGameState = 1;
        }
    }
}

现在,您可以在开始游戏活动时传递此状态:

public class MainMenu extends ActionBarActivity {

    ...

    public void continueGame() {
        Intent intent = new Intent(this, MainGame.class);
        intent.putExtra("TicTacToeData", mPreviousGameState);
        startActivityForResult(intent, 1);
    }
}

现在你需要一种方法来创建一个已经处于特定游戏状态的棋盘:

public class BoardFragment extends Fragment {
    public TicTacToe t = null

    ...

    public BoardFragment (int gameState) {
        t = new TicTacToe(gameState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            // recreate the board after an orientation change
            t = new TicTacToe(savedInstanceState.getInt("TicTacToeData"));
        } else if (t == null) {
            // create a new board if this is a new game
            // if this is a continued game, the board is already setup
            t = new TicTacToe();
        }
}

最后,您需要从游戏中调用BoardFragment的正确版本:

public class MainGame extends ActionBarActivity {

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_game);
        if (savedInstanceState == null) {
            Intent intent = getIntent();
            int gameState = intent.getIntExtra("TicTacToeData", -1);
            if (gameState == -1) {
                getSupportFragmentManager().beginTransaction().add(R.id.container, new BoardFragment()).commit();
            } else {
                getSupportFragmentManager().beginTransaction().add(R.id.container, new BoardFragment(gameState)).commit();
            }
        }
    }
}

答案 2 :(得分:1)

你需要做两件事:

  1. 当您的MainGame活动关闭时,在主课程内收到通知
  2. 更新用户界面以更改按钮文字
  3. 要在主要课程中收到通知:

    您可以使用MainGame代替startActivityForResult启动startActivity活动。然后覆盖Main类上的onActivityResult方法,以便在用户关闭MainGame时收到通知。

    此外,当用户单击后退按钮时,您必须修改MainGame以调用setResult(int resultCode, Intent data)setResult(int resultCode)方法(具体取决于您是否要将其他数据传递回活动)。

    覆盖MainGame类中的onBackPressed()方法以调用setResult方法。 E.g。

    public void onBackPressed() {
        setResult(RESULT_OK);
        super.onBackPressed(); // otherwise your Activity won't be closed
    }
    

    请查看http://developer.android.com/reference/android/app/Activity.html#StartingActivities以获取更详细的示例

    更新用户界面:

    1. 将按钮另存为本地变量(在o​​nCreate方法中)
    2. 更新按钮文字MainGame活动

       protected void onActivityResult(int requestCode, int resultCode,
               Intent data) {
           if (requestCode == PICK_CONTACT_REQUEST) {
               if (resultCode == RESULT_OK) {
                   // Update the button text to "Continue"
               } else {
                   // Change the button text back to "New Game"
               }
           }
       }
      

答案 3 :(得分:1)

另一种解决方案是重新设计您的应用,使每个要展示的屏幕只有一个Activity(或ActionBarActivity)子类和多个Fragment子类。您可以在Activity中保留对这两个片段的引用。这将隐式保留显示游戏板的片段的状态。