Java 从同一套接字读取的多线程
我正在开发一个显示服务器数据的应用程序。服务器不是我的,也不是很稳定。连接过多会使服务器崩溃 我的主活动中有一个到服务器的套接字,但有时我想打开读取数据并显示数据的子活动。我的问题是,我无法用同一个套接字实现这一点,必须为每个活动打开一个新的套接字。 每个活动都有一个线程,该线程从套接字读取数据,并根据需要更新该活动上的UI元素 为了在多个活动中使用同一套接字,我尝试在启动新活动之前关闭活动的inputReader,但这只会使应用程序挂起。如果我让它保持打开状态,那么新活动中的新线程永远不会收到任何数据。在启动新活动之前终止线程是不可能的,因为线程通常被read()函数阻塞 我是否可以有一个集中式线程来读取数据,然后将数据发送到其他活动中的所有其他线程,这样我就不必在每个活动中打开新的套接字Java 从同一套接字读取的多线程,java,android,multithreading,sockets,Java,Android,Multithreading,Sockets,我正在开发一个显示服务器数据的应用程序。服务器不是我的,也不是很稳定。连接过多会使服务器崩溃 我的主活动中有一个到服务器的套接字,但有时我想打开读取数据并显示数据的子活动。我的问题是,我无法用同一个套接字实现这一点,必须为每个活动打开一个新的套接字。 每个活动都有一个线程,该线程从套接字读取数据,并根据需要更新该活动上的UI元素 为了在多个活动中使用同一套接字,我尝试在启动新活动之前关闭活动的inputReader,但这只会使应用程序挂起。如果我让它保持打开状态,那么新活动中的新线程永远不会收到
我觉得这是我问的一个非常基本的问题,但我无法找到解决办法 基本上你自己回答了你的问题: 我可以有一个集中式线程来读取数据,然后将数据发送到其他活动中的所有其他线程 当然,这样的事情是可能的。但是你必须坐下来,设计并实现它。您可以从定义一个合理的接口开始,该接口允许您的其他线程与该中心服务进行通信,例如:
enum RequestType { DO_THIS, DO_THAT };
interface ServerConnectionService<T> {
List<T> performRequest(RequestType request);
}
enum RequestType{DO_THIS,DO_THAT};
接口服务器连接服务{
列出performRequest(请求类型请求);
}
意思是:不要让你的不同线程在这个套接字上进行“低级”对话,而是创建一个抽象,允许你说:“当我需要这种信息时,我就使用我的服务;它会向我返回一些特定的答案。”当然,这是一个非常通用的答案,但是你的问题也不是很具体
然后,下一步将是该接口的一些中心(可能是单例)实现;它在自己的线程上运行,并且可以由其他线程以同步的、定义良好的方式使用
最后一句警告:如果你没有拥有那台服务器,而且它的质量很低,给你带来了麻烦-这不是一个好的设置。因为无论你在代码中做了什么,如果服务器做得不好,用户都会认为你的应用程序是个问题。用户不在乎是否有操作n失败是因为某些远程服务器崩溃。因此,您的问题的另一个方面是:现在,您处于一个糟糕的境地。您应该花一些时间来寻找解决方法。否则,您将浪费大量时间为您正在处理的服务器构建变通方法。一个非常简单明了的方法ach如下所示:
服务
,该服务在后台运行,并通过套接字与服务器通信服务从套接字接收数据,并使用LocalBroadcastManager
BroadcastReceiver
,并在onReceive()方法中从服务
接收数据
stopService()停止服务
但是如果你不想/不需要服务的所有功能,你也可以做不同的事情。除了服务
之外,你还可以创建一个简单的线程
或HandlerThread
,与服务器进行通信。然后从线程内部,你可以将数据转发/广播到你的Act通过使用上述技术(LocalBroadcastManager
)进行ivities
仅举一个基本结构的示例(代码未经测试):
然后您就有了自己的活动,例如MyActivity1
,MyActivity2
,…MyActivityN
。它们都注册了嵌入的SocketDataReceiver
,以接收线程发送的广播意图SOCKET\u数据
在onReceive()
方法中,您可以使用标识符SOCKET\u data\u标识符从intent
对象中提取数据
public class MyActivity1 extends Activity
{
private SocketDataReceiver socketDataReceiver;
@Override
protected void onResume() {
super.onResume();
socketDataReceiver = new SocketDataReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(
socketDataReceiver, new IntentFilter(SocketThread.SOCKET_DATA_RECEIVED));
}
@Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(socketDataReceiver);
}
private class SocketDataReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent) {
// intent contains your socket data,
// get data from intent using SocketThread.SOCKET_DATA_IDENTIFIER
}
}
}
这似乎正是我所需要的。我将阅读所有这三件事。但我有一个问题。我需要服务还是线程呢?据我所知,当应用程序关闭时,服务将继续运行。我不需要这样做。只有当应用程序被使用时,我才需要显示信息。好的,给我一点时间t编辑我的答案以向您提供更多信息更新了答案,并提供了一个示例以帮助您入门,这对您很有帮助。谢谢:DJust一件事。这适用于任何其他在该线程结束的人。在该示例中,在发送部分,在初始化意图时,您必须将套接字\u数据\u接收字符串传递给cons好吧,不知怎么的。我想我的建议更进一步了,抽象出你的代码是如何与服务交互的。算了吧。你永远也做不到这一点。用一个线程读取套接字,让它把它的工作分派到你喜欢的任何线程/线程池/线程工作者系统
public class MyActivity1 extends Activity
{
private SocketDataReceiver socketDataReceiver;
@Override
protected void onResume() {
super.onResume();
socketDataReceiver = new SocketDataReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(
socketDataReceiver, new IntentFilter(SocketThread.SOCKET_DATA_RECEIVED));
}
@Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(socketDataReceiver);
}
private class SocketDataReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent) {
// intent contains your socket data,
// get data from intent using SocketThread.SOCKET_DATA_IDENTIFIER
}
}
}