在处理程序中执行某些操作后活动自我复制的原因是什么?



我正在开发一款使用蓝牙与其他设备连接的游戏。它是标准的客户机-服务器方案应用程序。

当玩家(其设备充当服务器)启动游戏时,活动启动。在它的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

最新更新