You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中Java线程循环执行两次Socket请求的问题及优化

问题分析与解决方案

你的代码存在几个关键问题,直接导致了第二个请求的阻塞:

  1. 发送requestB时,你新建了Socket,但仍在使用关联旧Socket的PrintWriter写数据,新Socket的输入流根本收不到设备响应,自然卡在readFully。
  2. 每次请求都重复创建Socket,不仅浪费资源,还容易引发连接异常。
  3. 直接在子线程调用TextView.setText,Android不允许子线程操作UI,会抛出异常。
  4. 最后关闭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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 00:01:16