Android中Java线程循环执行两次Socket请求的问题及优化
问题分析与解决方案
你的代码存在几个关键问题,直接导致了第二个请求的阻塞:
- 发送
requestB时,你新建了Socket,但仍在使用关联旧Socket的PrintWriter写数据,新Socket的输入流根本收不到设备响应,自然卡在readFully。 - 每次请求都重复创建Socket,不仅浪费资源,还容易引发连接异常。
- 直接在子线程调用
TextView.setText,Android不允许子线程操作UI,会抛出异常。 - 最后关闭Socket的代码存在语法错误(你定义的是单个
Socket对象,却用了数组下标socket[0])。
核心修复思路:复用Socket连接
不要每次请求都新建Socket,在循环外创建一次连接,复用其输入输出流完成多次请求响应,循环结束后统一关闭资源。
修改后的代码示例
public void ExecThread(String requestA, String requestB, TextView tv) { Runnable runnable = new Runnable() { String readA = null; String readB = null; int count = 5; byte[] bytesOf = new byte[255]; // 变量名遵循Java小驼峰规范 @Override public void run() { Socket socket = null; DataInputStream dis = null; PrintWriter output = null; try { // 仅创建一次Socket,复用连接 socket = new Socket(ip, port); OutputStream out = socket.getOutputStream(); output = new PrintWriter(out, true); dis = new DataInputStream(socket.getInputStream()); while (count != 0) { // 发送requestA并读取响应 output.println(requestA); // 改用read()替代readFully():避免设备返回字节不足255时无限阻塞 int readBytesA = dis.read(bytesOf, 0, 255); if (readBytesA > 0) { readA = new String(bytesOf, 0, readBytesA); // 仅转换实际读取的字节 } // 发送requestB并读取响应 output.println(requestB); int readBytesB = dis.read(bytesOf, 0, 255); if (readBytesB > 0) { readB = new String(bytesOf, 0, readBytesB); } // 必须回到主线程更新UI if (readA != null && readA.length() >= 250) { final String displayText = String.valueOf(count) + " - " + readA.substring(4, 16); tv.post(() -> tv.setText(displayText)); _fields.SetEkmFieldValueStrings(readA, readB); } count--; // 可选:添加请求间隔,避免频繁请求设备 // Thread.sleep(1000); } } catch (IOException | InterruptedException e) { e.printStackTrace(); } finally { // 统一关闭资源,避免泄漏 try { if (dis != null) dis.close(); if (output != null) output.close(); if (socket != null && !socket.isClosed()) socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }; new Thread(runnable).start(); }
关键注意事项
- 复用Socket连接:减少连接建立的开销,避免频繁创建连接导致的异常。
- 避免
readFully阻塞:如果设备返回的响应字节数不固定,用read()方法获取实际读取的字节数,不会强制等待满255字节才返回。 - 主线程更新UI:通过
TextView.post(Runnable)或Activity.runOnUiThread()回到主线程操作UI,符合Android的线程规范。 - 资源安全释放:用
finally块确保Socket、输入输出流在任何情况下都能被正确关闭,避免资源泄漏。 - 异常扩展处理:可根据实际需求添加连接失败重试、超时设置等逻辑,提升代码健壮性。
内容的提问来源于stack exchange,提问作者user16458899
相关产品推荐
相关产品推荐

