
本文讲解如何通过状态标记机制避免 android 应用中因 handler 回调或逻辑误触发导致的 sms 重复发送问题,核心是使用布尔标志位控制发送逻辑仅执行一次,并结合 ui 反馈与资源清理确保行为可控。
本文讲解如何通过状态标记机制避免 android 应用中因 handler 回调或逻辑误触发导致的 sms 重复发送问题,核心是使用布尔标志位控制发送逻辑仅执行一次,并结合 ui 反馈与资源清理确保行为可控。
在 Android 开发中,SmsManager.sendTextMessage() 本身是无状态、无去重能力的纯发送接口。若该方法被多次调用(例如在 Handler 的 handleMessage() 中未加防护地反复进入),就会导致短信重复发出——正如你在代码中观察到的:Toast 持续弹出、需强制退出应用才能终止,这正是典型的“缺乏发送状态管控”所致。
✅ 正确做法:引入发送状态标识
最简洁、可靠且符合 Android 生命周期习惯的方案,是在类作用域声明一个 boolean 标志位,并在真正发送前做原子性判断:
// 在 Activity 或 Service 类的成员变量区域声明
private boolean hasSentSMS = false;
// 修改你的 Handler 处理逻辑(关键修改处已高亮)
public Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.arg1 > 0) {
countingView.setText(" " + msg.arg1 +
context.getApplicationContext().getResources().getString(R.string.fall_contacts));
} else {
if (dialog != null) {
dialog.dismiss();
if (isVibrate) {
stopVibrate();
}
stopAlarm();
// ✅ 加入防重发保护
if (!hasSentSMS) {
sendSMS(locationAddress, locationTime);
hasSentSMS = true; // 发送后立即置为 true
}
return;
}
timer.cancel();
}
}
};同时,建议对 sendSMS() 方法本身也做轻量增强,例如添加空值校验与日志,提升健壮性:
private void sendSMS(String address, String time) {
if (address == null || time == null) {
Log.w("SMS", "Invalid address or time, SMS skipped");
return;
}
SmsManager smsManager = SmsManager.getDefault();
String name = sharedPreferences.getString("pre_key_name", "Unknown");
String phoneNum = sharedPreferences.getString("pre_key_phone", null);
if (phoneNum == null || phoneNum.trim().isEmpty()) {
Toast.makeText(context, "Phone number not configured", Toast.LENGTH_SHORT).show();
return;
}
String smsContent = time + name + " in " + address + " falls!";
smsManager.sendTextMessage(phoneNum, null, smsContent, null, null);
Toast.makeText(context, "SMS sent successfully", Toast.LENGTH_SHORT).show();
}⚠️ 注意事项与最佳实践
- 标志位重置时机需谨慎:当前方案中 hasSentSMS 一旦设为 true 就永久有效。如需支持「下次跌倒事件再次发送」,应在业务逻辑重启时(例如新检测周期开始、Activity 重建、或用户手动重置)显式置回 false;
- 不要依赖 return 跳出 Handler:你原代码中 return 仅结束当前 handleMessage() 执行,但 Handler 可能因定时器、消息队列等持续投递新 Message,故必须用状态变量拦截;
- 权限与兼容性提醒:自 Android 6.0(API 23)起,SEND_SMS 为危险权限,需动态申请;Android 12+(API 31)进一步限制后台发送能力,建议将 SMS 触发逻辑与前台 Activity 绑定,或改用 SmsRetrieverClient 等合规替代方案;
- 替代方案考虑:对于关键告警类短信,推荐结合 PendingIntent + BroadcastReceiver 监听 SMS_SENT 结果,实现发送结果闭环,而非仅依赖“调用即成功”。
通过这一小而关键的状态控制,即可彻底解决无限循环发送的问题,在保持代码简洁的同时,显著提升应用稳定性与用户体验。








