当应用程序进入后台时,实时多人 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 游戏实时多人游戏中的房间?