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

ESP8266与Android APP TCP通信问题:双向数据传输实现求助

实现Android与ESP8266 TCP服务器的双向通信

看起来你已经顺利搞定了ESP8266的TCP服务器配置(AT指令全返回OK就是最好的证明😉),接下来咱们把Android端的通信逻辑补全,实现ESP主动发0/1、APP接收后回传EditText内容的双向交互。

第一步:补全Android端基础配置

首先得给App加上必要的网络权限,在AndroidManifest.xml里添加:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

然后是对应你提到控件的布局文件activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="等待ESP数据..."
        android:textSize="18sp"/>

    <EditText
        android:id="@+id/txt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="输入要发送的文本"/>

    <EditText
        android:id="@+id/txt2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="备用输入框(按需使用)"/>

    <Button
        android:id="@+id/b"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送文本到ESP"/>
</LinearLayout>

第二步:完整的MainActivity代码实现

注意:Android禁止在主线程执行网络操作,所以咱们用协程处理网络逻辑(比AsyncTask更简洁现代)。另外你的原代码里string response要改成String response,Java是大小写敏感的哦。

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.Dispatchers;
import kotlinx.coroutines.launch;
import kotlinx.coroutines.withContext;

public class MainActivity extends AppCompatActivity {
    TextView tv;
    EditText txt, txt2;
    Button b;
    String espIp = "你的ESP8266局域网IP"; // 比如192.168.1.100,从ESP串口日志里找
    int espPort = 80;
    Socket socket;
    BufferedReader inputReader;
    OutputStreamWriter outputWriter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv = findViewById(R.id.tv);
        txt = findViewById(R.id.txt);
        txt2 = findViewById(R.id.txt2);
        b = findViewById(R.id.b);

        // 启动协程连接ESP并持续监听数据
        CoroutineScope(Dispatchers.IO).launch(() -> {
            try {
                socket = new Socket(espIp, espPort);
                inputReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                outputWriter = new OutputStreamWriter(socket.getOutputStream());

                // 循环读取ESP发来的0/1
                String espData;
                while ((espData = inputReader.readLine()) != null) {
                    final String receivedData = espData;
                    // 切回主线程更新UI
                    withContext(Dispatchers.Main) {
                        tv.setText("ESP发来数据:" + receivedData);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                withContext(Dispatchers.Main) {
                    tv.setText("连接失败:" + e.getMessage());
                }
            }
        });

        // 按钮点击事件:发送EditText内容到ESP
        b.setOnClickListener(v -> {
            String sendText = txt.getText().toString().trim();
            if (!sendText.isEmpty() && socket != null && socket.isConnected()) {
                CoroutineScope(Dispatchers.IO).launch(() -> {
                    try {
                        outputWriter.write(sendText + "\n"); // 加换行符让ESP识别数据结束
                        outputWriter.flush();
                        withContext(Dispatchers.Main) {
                            txt.setText(""); // 发送后清空输入框
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        withContext(Dispatchers.Main) {
                            tv.setText("发送失败:" + e.getMessage());
                        }
                    }
                });
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 销毁时关闭网络资源
        try {
            if (inputReader != null) inputReader.close();
            if (outputWriter != null) outputWriter.close();
            if (socket != null) socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

第三步:ESP8266端的补充逻辑

你已经完成了AT指令配置,现在需要在Arduino代码里实现客户端连接检测、定期发0/1、接收APP文本的逻辑:

#include <ESP8266WiFi.h>

const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";
WiFiServer server(80);
WiFiClient client;

void setup() {
  Serial.begin(115200);
  // 连接WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP()); // 这里的IP就是Android端要填的espIp
  server.begin();
}

void loop() {
  // 等待客户端连接
  if (!client.connected()) {
    client = server.available();
    if (client) {
      Serial.println("New client connected");
    }
  } else {
    // 每2秒发送一次0或1(可按需调整间隔)
    static unsigned long lastSendTime = 0;
    if (millis() - lastSendTime > 2000) {
      int sendData = random(0,2); // 随机生成0或1
      client.println(sendData); // 加换行符让Android端能读取
      lastSendTime = millis();
      Serial.println("Sent to APP: " + String(sendData));
    }

    // 读取APP发来的文本
    if (client.available() > 0) {
      String receivedText = client.readStringUntil('\n');
      Serial.println("Received from APP: " + receivedText);
      // 这里可以添加逻辑,比如根据文本控制LED等外设
    }
  }
}

关键注意事项

  • 确保Android设备和ESP8266在同一个局域网内
  • 替换代码中的WiFi名称、密码以及ESP的局域网IP(从ESP串口日志里获取)
  • 网络操作必须在子线程执行,否则会触发NetworkOnMainThreadException
  • 发送数据时建议加换行符(\n),方便两端识别数据结束位置

内容的提问来源于stack exchange,提问作者Malek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:17:44