Android Handler首次接收消息异常:为何首次丢失第二条线程消息?
从你贴的代码细节来看,首次运行丢了线程二的消息、再次运行却正常,大概率是这些隐藏的问题导致的:
空catch块吞了首次运行的异常
线程二的catch{}是空的,啥异常处理都没做。首次启动时,socket连接可能还没完全就绪,或者读取输入流时触发了IO异常(比如连接慢、数据流还没传过来),但异常被直接吞掉,导致后面的msg.sendToTarget()根本没执行。而再次运行时,socket连接已经稳定下来,读取过程没异常,消息就能正常发出去。bundle变量没初始化就用
线程二里直接写了msg.setData(bundle);,但完全没看到你初始化bundle的代码(比如Bundle bundle = new Bundle();)。如果bundle是null,虽然不会直接崩溃,但可能导致消息在传递时出隐性问题——首次运行时这种问题更容易触发,再次运行时可能因为状态变化避开了。数据流校验逻辑首次没通过
线程二里有个if(length!=check) continue;的判断,首次运行时,socket输入流可能只读到了部分数据,导致length和check不匹配,直接跳过了发消息的逻辑。而再次运行时,数据流已经有完整数据,校验通过,消息就能正常发送。另外,还要看看recive数组的长度够不够,如果数组太短,read()返回的长度肯定小于实际需要的长度,也会触发这个continue。Handler实例可能不统一(小概率但要确认)
线程一用的是HelpedHandle.obtainMessage(),线程二用的是handler.obtainMessage()。如果这俩不是同一个Handler实例,那线程一的消息其实是发给了另一个Handler,但你说首次收到了一个线程的消息,这应该不是主要问题,但最好确认两者是否绑定到同一个UI线程的Looper。
给你的排查建议
可以按这几步来定位和解决:
- 给catch块加日志:把
catch{}改成catch (IOException e) { e.printStackTrace(); Log.e("Thread2", "读取数据流出错", e); },这样就能看到首次运行时是不是真的抛出了异常。 - 初始化bundle:在创建msg之前,先写
Bundle bundle = new Bundle();,往bundle里塞完数据再调用msg.setData(bundle);。 - 检查recive数组长度:确保
recive数组的长度足够容纳协议规定的数据,避免一次读不全。 - 统一Handler实例:线程一和线程二尽量用同一个Handler来获取Message,比如都用
handler.obtainMessage(),避免因为Handler不一致发错消息。 - 优化数据流读取逻辑:socket的
read()不一定能一次读完整,建议循环读取直到拿到全部需要的字节,而不是只调用一次read()。
内容的提问来源于stack exchange,提问作者F.Eazism

