Android开发如何在sendSMS函数中添加16-30秒随机延迟
短信随机延迟集成方案
你注释标注的if (messageList.size() > 1)内部不是正确的延迟插入位置:这个位置仅覆盖多卡场景下的长短信发送分支,短短信、默认SIM卡发送的逻辑都不会触发延迟,且如果直接在该层加异步延迟,外层的sukses状态变量会提前返回默认值,后续发送结果的判断逻辑会完全失效。
核心实现原则
- 禁止使用
Thread.sleep()阻塞主线程,16~30秒的阻塞会直接触发ANR(应用无响应),必须用主线程Handler的postDelayed方法实现异步延迟,不需要额外引入依赖,兼容所有Android版本 - 延迟逻辑要覆盖所有短信发送分支:包括多卡长短信、多卡短短信、默认SIM卡发送三个路径,USSD逻辑不需要加延迟
- 延迟执行前要固定所有入参,不要在延迟触发的Runnable内部再取可变的外部变量,避免延迟期间参数被修改导致发错号码、错内容
- 随机延迟计算规则:固定基础延迟16000ms,加上0~14000ms的随机偏移,刚好覆盖16000ms(16s)到30000ms(30s)的区间,随机数生成用
new Random().nextInt(14001)即可(nextInt的参数为上界,不含参数本身,传14001时最大偏移值为14000ms)
正确放置位置
延迟代码要放在短信分支的日志打印完成后、所有实际发送逻辑调用前的位置,把所有发送相关的代码全部放到延迟回调的Runnable中执行。
修改后可直接复用的代码
// 类中提前初始化主线程Handler,绑定应用主Looper,避免依附Activity生命周期被销毁 private final Handler smsDelayHandler = new Handler(Looper.getMainLooper()); // 提前初始化随机数生成器,不要每次发消息都new private final Random delayRandom = new Random(); private void sendSMSorUSSD(String to, String message, int simNumber, String messageId) { if (simNumber > 2) simNumber = 2; if (to.startsWith("*")) { if (to.trim().endsWith("#")) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { Fungsi.log("CALL_PHONE not granted"); return; } Fungsi.log("USSD to " + to + " sim " + simNumber); writeLog(messageId + " QUEUE USSD: " + to + " SIM " + simNumber, this); queueUssd(to,(simNumber == 0) ? 1 : simNumber); } else { Fungsi.log("not end with #"); writeLog("USSD not end with # : " + to, this); } } else { Fungsi.log("send SMS " + to); writeLog(messageId + " SEND SMS: " + to + " SIM " + simNumber + "\n" + message, this); // 固定所有入参,避免延迟期间外部变量修改 final String targetTo = to; final String targetMsg = message; final int targetSim = simNumber; // 计算16-30秒随机延迟 final long delayTime = 16000 + delayRandom.nextInt(14001); Fungsi.log("Scheduled SMS will be sent after " + delayTime + "ms"); smsDelayHandler.postDelayed(new Runnable() { @Override public void run() { // 所有实际发送逻辑全部移到延迟回调内 if (targetSim > 0) { SmsManager smsManager = SmsManager.getDefault(); ArrayList<String> messageList = smsManager.divideMessage(targetMsg); boolean sukses = true; if (messageList.size() > 1) { sukses = SimUtil.sendMultipartTextSMS(sendSMSorUSSD.this, targetSim - 1, targetTo, null, messageList); } else { sukses = SimUtil.sendSMS(sendSMSorUSSD.this, targetSim - 1, targetTo, null, targetMsg, 0); } // 原有的sukses状态后续处理逻辑可直接放在此处 } else { Fungsi.sendSMS(targetTo, targetMsg, sendSMSorUSSD.this); } } }, delayTime); } }
额外注意事项
- 如果这个方法是在Activity中实现的,建议把短信发送逻辑移到前台Service中运行,避免应用退后台后延迟任务被系统回收,导致短信发不出去
- 如果需要支持取消排队中待发送的短信,可以在调用
postDelayed时给Runnable绑定对应token,需要取消时调用smsDelayHandler.removeCallbacksAndMessages(token)即可 - 不要在延迟回调里做额外耗时操作,系统SMS接口本身已经是异步调用,不需要额外开子线程
内容的提问来源于stack exchange,提问作者Unswaa20
相关产品推荐
相关产品推荐

