Search code examples
androidnode.jsandroid-activitysocket.ioconnection-pooling

How to share socket.io connection between Android activities?


In socket.io Android client example project we read that:

IO.socket() returns a socket for http://chat.socket.io with the default options. Notice that the method caches the result, so you can always get a same Socket instance for an url from any Activity or Fragment.

So I decided to test that, because number of opened sockets on my server was not equal to number of clients.

I used following server:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req, res){
    res.sendfile('index.html');
});

io.on('connection', function(socket){
    console.log('- connect event '+socket.id);
    socket.on('disconnect', function () {
        console.log('- disconnect event from id '+socket.id);
    });
});

http.listen(3000, '0.0.0.0', function(){
    console.log('. listening on *:3000');
});

And developed a very simple Android app, that contains two activities, each opens socket.io connection to the same server address and permits to simply switch between activities.

I start the server and launch the app, this is the output I get.

. listening on *:3000
( now I launch the app, opens Activity A )
- connect event 1FIizV3QMdGmnYUQAAAA
( I switch from Activity A to Activity B )
- connect event IzllGFxbpzI5NPNiAAAB
( I switch back from Activity B to Activity A )
- connect event pNt8Yvom5Rih_-01AAAC
- disconnect event from id 1FIizV3QMdGmnYUQAAAA
- disconnect event from id IzllGFxbpzI5NPNiAAAB

This simple test suggests that when onDestroy event inside the activity I turn off callbacks, socket connection is destroyed, when I restore the activity a new socket connection is opened, but it contradicts so you can always get a same Socket instance for an url from any Activity or Fragment stated above, because it seems that new instance is being created.

Question

It seems that multiple activity model is very common in Android development ( many people suggest it is inefficient to simply change Fragments over and over again ), how to efficiently share a socket connection between such activities, so that server could have the same socket connection for client no matter how many activities it contains?

Option I considered was creating a BoundService that would handle all the callbacks and events for socket connection and all Activities could share this service, however I did not find an efficient way of communicating with such service. IPC (inter process communication) in such case could be a huge slow-down, especially if it is based on Intents.

I hope I can get some help on making my app more pro and that it will also be useful for others.


Solution

  • You can use a Service to handle the socket and use a Binder to communicate with the service via arbitrary methods instead of via Intents. I'm assuming you already know how to work with a started and/or bound Service, if not - read the guide.

    You need to override the Service's onBind callback and return a custom subclass of the Binder class, which exposes an API for controlling the socket, registering callbacks and the like.

    Here's what the code for your Binder would probably look like:

    private final IBinder socketBinder = new SocketBinder();
    
    @Override
    public IBinder onBind(Intent intent) {
        return socketBinder;
    }
    
    public class SocketBinder extends Binder {
        // Now you have access to all your Service's public methods
        public SocketService getService() {
            return SocketService.this;
        }
    }