Android TCP客户端无法向Python服务器发送Beacon RSSI数据求助
问题分析与解决方案
先直接戳中你的核心问题:你把网络等待、数据发送逻辑塞进了getView()方法里,而getView()是运行在UI线程的,这直接导致UI线程被阻塞,不仅会引发ANR(应用无响应),还让你的数据发送逻辑彻底混乱。
核心问题拆解
- UI线程阻塞:
getView()里的while(serveractivate == 0)循环会死死卡住UI线程——UI线程被用来等待Socket连接,完全违背Android线程规范,后续发送逻辑自然无法正常执行,甚至整个界面都会卡死。 - 逻辑位置错误:数据收集、Socket发送这类业务逻辑绝对不能放在
getView()中,因为系统会在列表滚动、数据更新时频繁调用getView(),这会导致你的连接、拼接、发送逻辑被重复触发,出现不可控的混乱。 - 线程安全隐患:
serveractivate、stackcnt这些变量没有做线程同步,在UI线程和Socket线程之间交叉访问,很容易出现状态判断错误。
修复方案
1. 重构Socket与数据发送逻辑
把所有网络操作移到独立后台线程,绝对不能占用UI线程。同时将Beacon数据收集、发送逻辑从Adapter中剥离,放到MainActivity或专门的业务管理类中。
2. 简化Adapter职责
Adapter只负责展示数据,不处理任何业务逻辑(网络、数据收集),彻底避免getView()频繁调用带来的逻辑混乱。
3. 代码修改示例
第一步:重构MainActivity,新增数据发送管理类
public class MainActivity extends Activity implements BeaconCallback, Runnable { // ... 原有代码保持不变 ... private BeaconDataSender beaconDataSender; // 新增:专门的发送器 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ... 原有代码 ... beaconDataSender = new BeaconDataSender(); // 初始化发送器 beaconDataSender.connectToServer(); // 启动后台连接 } @Override public void onBeaconCallback(int status, Beacon beacon) { switch (status) { case STATUS_CODE_ENTER: case STATUS_CODE_UPDATE: if (adapter != null) adapter.addBeacon(beacon); // 新增:把Beacon数据传给发送器 beaconDataSender.addBeaconData(beacon.getRssi()); break; case STATUS_CODE_EXIT: if (adapter != null) adapter.removeBeacon(beacon); // 新增:移除对应数据(可选) beaconDataSender.removeBeaconData(beacon.getMac()); break; default: break; } runOnUiThread(this); } // ... 原有代码 ... @Override protected void onPause() { super.onPause(); contextManager.stopLeScan(); beaconDataSender.stopSocket(); // 新增:断开连接 } // 新增:专门负责Beacon数据发送的内部类 private class BeaconDataSender { private Socket socket = null; private PrintWriter out = null; private final int PORT = 9999; private final String SERVER_IP = "192.168.0.4"; private final int TARGET_BEACON_COUNT = 2; private final List<Integer> rssiList = Collections.synchronizedList(new ArrayList<>()); private boolean isConnected = false; // 后台连接服务器 public void connectToServer() { new Thread(() -> { try { socket = new Socket(SERVER_IP, PORT); socket.setTcpNoDelay(true); out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))); isConnected = true; Log.w("state ", "server connected"); } catch (IOException e) { Log.w("state ", "failed to connect server"); e.printStackTrace(); } }).start(); } // 添加Beacon RSSI数据 public void addBeaconData(int rssi) { if (rssiList.size() >= TARGET_BEACON_COUNT) { rssiList.clear(); } rssiList.add(rssi); // 当收集到目标数量的数据时,发送 if (rssiList.size() == TARGET_BEACON_COUNT && isConnected) { sendRssiData(); } } // 移除指定Beacon的数据(可选) public void removeBeaconData(String mac) { // 如果需要根据MAC跟踪数据,这里可以调整逻辑 if (!rssiList.isEmpty()) { rssiList.remove(0); } } // 发送数据到服务器 private void sendRssiData() { if (out == null || !isConnected) return; new Thread(() -> { StringBuilder sb = new StringBuilder(); for (int rssi : rssiList) { sb.append(rssi).append(" "); } String sendStr = sb.toString().trim(); try { out.println(sendStr); out.flush(); Log.d("sendrssi ", sendStr); rssiList.clear(); // 发送后清空列表 } catch (Exception e) { e.printStackTrace(); isConnected = false; // 可选:尝试重连 connectToServer(); } }).start(); } // 断开连接 public void stopSocket() { try { if (out != null) { out.close(); } if (socket != null && !socket.isClosed()) { socket.close(); } isConnected = false; } catch (IOException e) { e.printStackTrace(); } } } }
第二步:简化BeaconListAdapter,只负责展示
public class BeaconListAdapter extends BaseAdapter { private final LayoutInflater inflater; private int count; private final ArrayMap<String, Beacon> itemMap = new ArrayMap<>(); private final int padding; public BeaconListAdapter(Context context) { super(); padding = (int) context.getResources().getDimension(R.dimen.activity_vertical_margin); this.inflater = LayoutInflater.from(context); } public int addBeacon(Beacon beacon) { synchronized (itemMap) { itemMap.put(beacon.getMac(), beacon); count = itemMap.size(); return count; } } public int removeBeacon(Beacon beacon) { synchronized (itemMap) { itemMap.remove(beacon.getMac()); count = itemMap.size(); return count; } } @Override public int getCount() { return count; } @Override public Beacon getItem(int position) { synchronized (itemMap) { return itemMap.valueAt(position); } } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { TextView textView = null; if (convertView == null) { convertView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false); textView = (TextView) convertView.findViewById(android.R.id.text1); textView.setBackgroundColor(Color.WHITE); textView.setTextColor(Color.BLACK); textView.setPadding(padding, padding, padding, padding); convertView.setTag(textView); } else { textView = (TextView) convertView.getTag(); } Beacon item = getItem(position); int temprssi = item.getRssi(); int[] values = BeaconUtils.getAccelerometer(item); // 只负责展示数据,去掉所有网络和发送逻辑 textView.setText(String.format("[%s]\nMAC : %s\nRssi : %d\n", item.getType() == Beacon.TYPE_MIDAS ? "Midascon" : "Beacon", item.getMac(), temprssi)); return convertView; } }
关键优化点说明
- 线程隔离:所有网络操作(连接、发送)都放在后台线程,UI线程只负责界面更新和数据收集通知,彻底避免阻塞。
- 职责分离:Adapter专注UI展示,数据收集和发送交给专门类处理,代码结构更清晰,逻辑更可控。
- 线程安全:用
Collections.synchronizedList保证RSSI列表的线程安全,避免多线程访问异常。 - 稳定可靠:移除了
getView()中的死循环,界面流畅度和稳定性大幅提升。
内容的提问来源于stack exchange,提问作者jason
相关产品推荐
相关产品推荐

