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

Posted

技术标签:

【中文标题】当应用程序进入后台时,实时多人 Google Play 游戏服务对等方断开连接【英文标题】:Real-time Multiplayer Google Play Games Services peer gets disconnected when app goes in background 【发布时间】:2017-11-15 01:47:36 【问题描述】:

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

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

我添加了代码 sn-ps 以提供更好的理解。

@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());
                    
                
            
        ;

感谢任何帮助。谢谢。

【问题讨论】:

【参考方案1】:

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 中停止。这可能是一个不错的选择,但我还没有真正尝试过。

【讨论】:

将 gameHelper.onStop 移动到 on destroy 对我有用。

以上是关于当应用程序进入后台时,实时多人 Google Play 游戏服务对等方断开连接的主要内容,如果未能解决你的问题,请参考以下文章

如何检测客户端是不是故意离开 Google Play 游戏实时多人游戏中的房间?

Google Play 服务实时多人游戏的共享种子?

当应用程序进入后台时如何停止可运行?

为啥实时多人游戏测试应用程序 ButtonClicker2000 在启动时崩溃?

如何同步播放服务实时多人游戏

具有不同角色的实时多人 Google Play 游戏