Лучшие решения для Android Socket.IO для поддержания связи

My Android приложение использует библиотеку AndroidAsync для подключения к серверу Node.js с клиентом Socket.IO. Клиент сокета устанавливается через службу.

  • Сокет должен оставаться открытым/подключенным, когда приложение открыто.
  • Socket может закрыться, когда приложение не открыто.
  • Существует одно исключение, где сокет должен оставаться открытым, пока приложение не открыто.

В настоящее время я запускаю службу Socket.IO в onResume и останавливаюсь в onPause каждого Activity в приложении.

Это кажется действительно неэффективным, потому что я в основном останавливаю сокет и воссоздаю новый каждый раз, когда нажимаю кнопку "домой", или переключаюсь на другую активность в приложении.

Каким будет лучший способ справиться с вышеуказанными требованиями о том, чтобы держать сокет открытым?

public class SocketIOService extends Service {

    private Preferences prefs;
    private SocketIOClient socket;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            ConnectCallback callback = new ConnectCallback() {
                @Override
                public void onConnectCompleted(Exception ex, SocketIOClient client) {
                    if (ex != null) {
                        ex.printStackTrace();
                        return;
                    }

                    Log.v("SOCKET IO CONNECTION", "ESTABLISHED");

                    client.setDisconnectCallback(new DisconnectCallback() {
                        @Override
                        public void onDisconnect(Exception e) {
                            Log.v("SOCKET IO CONNECTION", "TERMINATED");
                        }
                    });

                    client.setErrorCallback(new ErrorCallback() {
                        @Override
                        public void onError(String error) {
                            Log.e("SOCKET IO ERROR", error);
                        }
                    });

                    client.setExceptionCallback(new ExceptionCallback() {
                        @Override
                        public void onException(Exception e) {
                            e.printStackTrace();
                        }
                    });

                    client.setReconnectCallback(new ReconnectCallback() {
                        @Override
                        public void onReconnect() {
                            Log.v("SOCKET IO CONNECTION", "RECONNECTED");
                        }
                    });

                    client.on(EVENT_NEWS, new EventCallback() {
                        @Override
                        public void onEvent(JSONArray argument, Acknowledge acknowledge) {
                            Log.v("EVENT:NEWS", argument.toString());
                        }
                    });

                    client.on(EVENT_MESSAGE_RECEIVE, new EventCallback() {
                        @Override
                        public void onEvent(JSONArray argument, Acknowledge acknowledge) {
                            handleMessageReceive(argument);
                        }
                    });

                }
            };

            socket = SocketIOClient.connect(AsyncHttpClient.getDefaultInstance(), URL_SERVER, callback).get();

            JSONArray array = new JSONArray();
            JSONObject obj = new JSONObject();
            prefs = new Preferences(this);
            try {
                obj.put(KEY_USER_ID, prefs.getUserId());
            } catch (JSONException e) {
                e.printStackTrace();
            }
            array.put(obj);
            socket.emit(EVENT_LOG_USER_ID, array);

            Log.v("SOCKET LOG USER ID", array.toString());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        // If we get killed, after returning from here, restart
        return START_REDELIVER_INTENT;
    }

    @Override
    public void onDestroy() {
        Log.v("SOCKET IO SERVICE", "STOPPED");
        if (socket != null) {
            if (socket.isConnected()) {
                socket.disconnect();
            }
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void handleMessageReceive(JSONArray json) {
        ChatMessage message = JReader.createMessage(json);
    }

}

Ответ 1

У меня есть частичное решение (не решит ваше третье требование, я думаю). Я начал писать простую многопользовательскую игру только для изучения игрового программирования. Я решил использовать TCP-соединение (почему? Его еще одна проблема...), и мне пришлось поддерживать соединение открытым, пока пользователь продолжал работу в каждой Acitivty (логин → лобби → выбор противника...) Я использовал Singleton patthern (проверка с двойной блокировкой), содержащую сокет подключения.

псевдокод

class ClientConnection{
    private static ClientConnection conn = null;
    Socket mSocket; // your socket  
    protected ClientConnection(){
        mSocket = new Socket();
        // mSocket.connect( bla bla bla ) 

    }

    public Socket getSocket(){
        return mSocket();
    }
    public static ClientConnection getInstance(){
        if(conn == null){
            synchronized (LOCK) {
                if(conn == null){
                    conn = new ClientConnection();
                }
            }
        }
        return conn;        
    }
}