实时多人游戏 Google 当应用程序进入后台时,Play 游戏服务对等点断开连接

Real-time Multiplayer Google Play Games Services peer gets disconnected when app goes in background

我正在使用 'Google Play Games Services' 构建实时多人游戏。我的问题是,当对等点连接到一个房间并玩游戏时,其中一个将他们的应用程序置于后台,该对等点与房间断开连接,而其他对等点收到该对等点离开房间的回调,这是他们防止的一种方法这不会发生。

出于测试目的,片段不会在其任何生命周期方法中调用离开该房间。

我添加了代码片段以提供更好的理解。

@Override
    public void onStop() {
        super.onStop();
//        if (mRoomId!=null && !mRoomId.isEmpty()) {
//            Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, mRoomId);
//        }
//        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//        mPlaying = false;
    }

        @Override
            public void onActivityResult(int request, int response, Intent data) {
                if (request == RC_SELECT_PLAYERS) {
                    if (response != Activity.RESULT_OK) {
                        // user canceled
                        return;
                    }

                    // get the invitee list
                    Bundle extras = data.getExtras();
                    final ArrayList<String> invitees =
                            data.getStringArrayListExtra(Games.EXTRA_PLAYER_IDS);

                    // get auto-match criteria
                    Bundle autoMatchCriteria = null;
                    int minAutoMatchPlayers =
                            data.getIntExtra(Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
                    int maxAutoMatchPlayers =
                            data.getIntExtra(Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);

                    if (minAutoMatchPlayers > 0) {
                        autoMatchCriteria = RoomConfig.createAutoMatchCriteria(
                                minAutoMatchPlayers, maxAutoMatchPlayers, 0);
                    } else {
                        autoMatchCriteria = null;
                    }

                    // create the room and specify a variant if appropriate
                    RoomConfig.Builder roomConfigBuilder = makeBasicRoomConfigBuilder();
                    roomConfigBuilder.addPlayersToInvite(invitees);
                    if (autoMatchCriteria != null) {
                        roomConfigBuilder.setAutoMatchCriteria(autoMatchCriteria);
                    }
                    RoomConfig roomConfig = roomConfigBuilder.build();
                    Games.RealTimeMultiplayer.create(((MainActivity) getActivity()).getGoogleApiClient(), roomConfig);

                    // prevent screen from sleeping during handshake
                    getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                }

                if (request == RC_WAITING_ROOM) {
                    if (mWaitingRoomFinishedFromCode) return;

                    if (response == Activity.RESULT_OK) {
                        // (start game)
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                if (getContext()!=null) {
                                    Player[] players = getParticipantPlayers();
                                    if (players!=null && players.length>0) {
                                        startGame(players);
                                    }
                                }
                            }
                        }, 1000);
                    }
                    else if (response == Activity.RESULT_CANCELED) {
                        // Waiting room was dismissed with the back button. The meaning of this
                        // action is up to the game. You may choose to leave the room and cancel the
                        // match, or do something else like minimize the waiting room and
                        // continue to connect in the background.

                        // in this example, we take the simple approach and just leave the room:
                        Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, mRoomId);
                        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                    }
                    else if (response == GamesActivityResultCodes.RESULT_LEFT_ROOM) {
                        // player wants to leave the room.
                        Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, mRoomId);
                        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                    }
                }
            }

    private RoomUpdateListener roomUpdateListener = new RoomUpdateListener() {

            @Override
            public void onJoinedRoom(int statusCode, Room room) {
                if (getContext()!=null) {
                    roomCreatorId = room.getCreatorId();
                    mRoomId = room.getRoomId();
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
    //            setCurrentPlayerParticipantId();
                    if (statusCode != GamesStatusCodes.STATUS_OK) {
                        // let screen go to sleep
                        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

                        // show error message, return to main screen.
                        Toast.makeText(getContext(), "Error while joining room.", Toast.LENGTH_SHORT).show();
                        showRoomUi();
                    }

                    // get waiting room intent
                    Intent i = Games.RealTimeMultiplayer.getWaitingRoomIntent(((MainActivity) getActivity()).getGoogleApiClient(), room, MIN_PLAYERS);
                    startActivityForResult(i, RC_WAITING_ROOM);
                }
            }

            @Override
            public void onRoomCreated(int statusCode, Room room) {
                if (getContext()!=null) {
                    roomCreatorId = room.getCreatorId();
                    mRoomId = room.getRoomId();
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
    //            setCurrentPlayerParticipantId();
                    if (statusCode != GamesStatusCodes.STATUS_OK) {
                        // let screen go to sleep
                        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

                        // show error message, return to main screen.
                        Toast.makeText(getContext(), "Error creating room.", Toast.LENGTH_SHORT).show();
                        showRoomUi();
                    }

                    // get waiting room intent
                    Intent i = Games.RealTimeMultiplayer.getWaitingRoomIntent(((MainActivity) getActivity()).getGoogleApiClient(), room, MIN_PLAYERS);
                    startActivityForResult(i, RC_WAITING_ROOM);
                }
            }


            @Override
            public void onLeftRoom(int i, String s) {
                if (getContext()!=null) {
    // remove the flag that keeps the screen on
                    mRoomId = null;
                }
            }

            @Override
            public void onRoomConnected(int statusCode, Room room) {
                if (getContext()!=null) {
                    roomCreatorId = room.getCreatorId();
                    mRoomId = room.getRoomId();
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
    //            setCurrentPlayerParticipantId();
                    if (statusCode != GamesStatusCodes.STATUS_OK) {
                        // let screen go to sleep
                        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

                        // show error message, return to main screen.
                        Toast.makeText(getContext(), "Error connecting to room.", Toast.LENGTH_SHORT).show();
                        showRoomUi();
                    }
                }
            }

        };


        private RoomStatusUpdateListener roomStatusUpdateListener = new RoomStatusUpdateListener() {

            @Override
            public void onRoomConnecting(Room room) {
                if (getContext()!=null) {
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
                }
            }

            @Override
            public void onRoomAutoMatching(Room room) {
                if (getContext()!=null) {
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
                }
            }

            @Override
            public void onPeerInvitedToRoom(Room room, List<String> list) {
                if (getContext()!=null) {
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
                }
            }

            @Override
            public void onPeerJoined(Room room, List<String> list) {
                if (getContext()!=null) {
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
                }
            }

            @Override
            public void onConnectedToRoom(Room room) {
                if (getContext()!=null) {
                    mMyId = room.getParticipantId(Games.Players.getCurrentPlayerId(((MainActivity) getActivity()).getGoogleApiClient()));
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
                }
            }

            @Override
            public void onDisconnectedFromRoom(Room room) {

                if (getContext()!=null) {
    // leave the room
                    Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, room.getRoomId());

                    // clear the flag that keeps the screen on
                    getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

                    // show error message and return to main screen
                    Toast.makeText(getContext(), "Network error.", Toast.LENGTH_SHORT).show();

                    showRoomUi();
                }

            }

            @Override
            public void onP2PConnected(String s) {
            }

            @Override
            public void onP2PDisconnected(String s) {
            }

            @Override
            public void onPeersConnected(Room room, List<String> peers) {
                if (getContext()!=null) {
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
                    if (mPlaying) {
                        // add new player to an ongoing game
                    } else if (shouldStartGame(room)) {
                        // start game!
                    }
                }
            }

            @Override
            public void onPeersDisconnected(Room room, List<String> peers) {
                if (getContext()!=null) {
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
                    if (mPlaying) {
                        // do game-specific handling of this -- remove player's avatar
                        // from the screen, etc. If not enough players are left for
                        // the game to go on, end the game and leave the room.
                    }
                    else if (shouldCancelGame(room)) {
                        // cancel the game
                        Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, room.getRoomId());
                        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                        showRoomUi();
                    }
                }
            }

            @Override
            public void onPeerLeft(Room room, List<String> peers) {
                if (getContext()!=null) {
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
                    // peer left -- see if game should be canceled
                    if (!mPlaying && shouldCancelGame(room)) {
                        Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, room.getRoomId());
                        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                        showRoomUi();
                    }
                }
            }

            @Override
            public void onPeerDeclined(Room room, List<String> peers) {
                if (getContext()!=null) {
                    mParticipants.clear();
                    mParticipants.addAll(room.getParticipants());
                    // peer declined invitation -- see if game should be canceled
                    if (!mPlaying && shouldCancelGame(room)) {
                        Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, room.getRoomId());
                        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                        showRoomUi();
                    }
                }
            }

        };

        private RealTimeMessageReceivedListener realTimeMessageReceivedListener = new RealTimeMessageReceivedListener() {
            @Override
            public void onRealTimeMessageReceived(RealTimeMessage realTimeMessage) {
                if (getContext()!=null) {
                    if (realTimeMessage.isReliable()) {
                        handleReliableMessages(realTimeMessage.getMessageData());
                    }
                }
            }
        };

感谢任何帮助。谢谢。

AFAIK,这就是 API 的设计方式和预期的工作方式。

如本 documentation 所述,只要您的游戏进入后台,您就应该离开活动房间。

如需更多见解(来自 Bruno Oliveira),您可能希望查看这些相关的 SO 帖子:

  • When a peer disconnected from a room in google play services
  • Google Play Game Services - How to Not Leave Room onPause

不过,您也可以选择尝试这个 suggested solution。尝试编辑 BaseGameActivity.onStop() 并删除 gamehelper.onStop()。有了这个,gamesclient 只会在 onDestroy 停止。这可能是个不错的选择,但我还没有真正尝试过。