[英]Real-time Multiplayer Google Play Games Services peer gets disconnected when app goes in background
I am building a real time multiplayer game using 'Google Play Games Services'. 我正在使用“Google Play游戏服务”构建实时多人游戏。 My question is that when peers are connected to a room and playing the game, and one of them puts their application in background that peer gets disconnected from room, and other peers receives callback of that peer leaving the room, is their a way to prevent this from happening.
我的问题是,当同伴连接到一个房间并玩游戏时,其中一个将他们的应用程序置于后台,同伴与房间断开连接,而其他同伴收到该同伴离开房间的回调,是他们的一种预防方法这发生了。
For testing purpose fragment does not call to leave that room in any of its life cycle methods. 出于测试目的,片段不会调用在任何生命周期方法中离开该房间。
I've added code snippets to provide better understanding. 我添加了代码片段以提供更好的理解。
@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());
}
}
}
};
Any help is appreciated. 任何帮助表示赞赏。 Thank you.
谢谢。
AFAIK, that's just how the API was designed and is working as intended. AFAIK,这就是API的设计方式和工作方式。
As mentioned in this documentation , you should leave the active room whenever your game goes into the background. 如本文档中所述 ,每当游戏进入后台时,您应该离开活动室。
For additional insights (from Bruno Oliveira ), you may want to see these related SO posts: 有关其他见解(来自Bruno Oliveira ),您可能希望查看这些相关的SO帖子:
Though, you may also opt to try this suggested solution . 不过,您也可以选择尝试这种建议的解决方案 。 Try editing
BaseGameActivity.onStop()
and remove gamehelper.onStop()
. 尝试编辑
BaseGameActivity.onStop()
并删除gamehelper.onStop()
。 With this, gamesclient
will only stopped in onDestroy
. 有了这个,
gamesclient
将只停在onDestroy
。 It might be a good option but I haven't actually tried it. 这可能是一个不错的选择,但我还没有尝试过。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.