我正在通过创建测试项目来学习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());
}
}
}
感谢您的帮助。
答案 0 :(得分:1)
您有两个选择
SharedPreferences
:您可以使用shaerdPreferences来存储游戏状态。它也会在重新启动应用程序后存储。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)
你需要做两件事:
要在主要课程中收到通知:
您可以使用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以获取更详细的示例
更新用户界面:
更新按钮文字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
中保留对这两个片段的引用。这将隐式保留显示游戏板的片段的状态。