如何在 Android 个活动之间共享 socket.io 连接?

How to share socket.io connection between Android activities?

在 socket.io Android 客户 example 项目中我们读到:

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.

所以我决定测试一下,因为我的服务器上打开的套接字数量不等于客户端数量。

我使用了以下服务器:

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');
});

并开发了一个非常简单的 Android 应用程序,它包含两个活动,每个活动都打开 socket.io 到同一服务器地址的连接,并允许在活动之间简单地切换。

我启动服务器并启动应用程序,这是我得到的输出。

. 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

这个简单的测试表明,当 activity 中的 onDestroy 事件关闭回调时,套接字连接被破坏,当我恢复 activity 时,一个新的套接字连接被打开,但它与上述so you can always get a same Socket instance for an url from any Activity or Fragment相矛盾,因为似乎正在创建新实例。

问题

似乎activity开发中多activity模型很常见(很多人认为简单地一遍又一遍地更改Fragment效率低下),如何高效地共享一个套接字连接这样的活动,以便服务器可以为客户端拥有相同的套接字连接,无论它包含多少活动?

我考虑的选项是创建一个 BoundService 来处理套接字连接的所有回调和事件,并且所有 Activity 都可以共享此服务,但是我没有找到与此类服务通信的有效方式。 IPC(进程间通信)在这种情况下可能会大大降低速度,特别是如果它基于 Intents。

我希望我能得到一些帮助,使我的应用程序更专业,并且它对其他人也有用。

您可以使用 Service 来处理套接字并使用 Binder 通过任意方法而不是通过 Intents 与服务通信。我假设您已经知道如何使用已启动的 and/or 绑定服务,如果还不知道 - read the guide.

您需要覆盖服务的 onBind callback and return a custom subclass of the Binder class,它公开一个 API 用于控制套接字、注册回调等。

您的 Binder 的代码可能如下所示:

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;
    }
}