我正在开发一款使用蓝牙与其他设备连接的游戏。它是标准的客户机-服务器方案应用程序。
当玩家(其设备充当服务器)启动游戏时,活动启动。在它的onCreate方法中,我设置并显示了一个ProgressDialog
。这个对话框一直出现直到其他玩家连接。在这个活动中,还有Handler
,它从管理蓝牙连接的后台线程接收消息。当第一个玩家加入游戏时,处理程序收到适当的消息,然后我开始初始化游戏,这意味着我在setContendView(View v)
中解散ProgressDialog并加载布局。这是一个问题,因为它通常运行良好,但有时会创建新的活动实例(而原来的活动仍然存在),并接管游戏管理。这不会是一个大问题,但是当游戏结束时,这个新活动完成了,原来的活动在顶部,当我试图关闭它时,应用程序崩溃了。
我认为这是因为在错误的地方使用setContendView(View v)
,但即使另一个玩家在游戏期间加入(然后setContendView(View v)
不再被调用),这种情况也会发生,所以在极端情况下,三个活动实例同时存在,导致大多数玩家的混乱和崩溃。
代码示例:
public void onCreate(Bundle savedInstanceState) {
pDialog = new ProgressDialog(this);
pDialog.setMessage("...");
pDialog.setCancelable(false);
pDialog.setCanceledOnTouchOutside(false);
pDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
context.getString(R.string.alert_button_cancel),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
pDialog.dismiss();
finishActivity();
}
});
pDialog.show();
}
和处理程序:
public void handleMessage(Message message) {
if(message.what == Constants.MESSAGE_NEW_PLAYER) {
NewPlayerMessage m = (NewPlayerMessage) message.obj;
if(pDialog != null && pDialog.isShowing()) {
pDialog.dismiss();
}
BluetoothService.broadcast(new PlayersUpdateMessage(game.getAllPlayersFields()));
BluetoothService.broadcast(game.addMessage(new ChatMessage(m.getAddress(), ChatMessage.PLAYER_JOIN)));
if (game.getDrawingPlayerAddr().equals("")){
game.setDrawingPlayerAddr(BluetoothService.MY_ADDRESS);
//...
setGameMode(true);
setGameTimer(game.getRoundTime());
}
}
//...
}
其中setGameMode()
包含前面提到的setContendView(View v)
以及按钮和其他布局元素的初始化。
为了避免创建重复的活动,您应该设置属性launchMode为
android:launchMode="singleTask"
下面是另一个例子:
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTask" />
这将在新任务的根创建活动,并将意图路由到它。但是,如果活动的实例已经存在,系统将通过调用其onNewIntent()方法将意图路由到现有的实例,而不是创建一个新的
每个可用选项的详细信息见:
http://developer.android.com/guide/topics/manifest/activity-element.html