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

Android Studio接收SMS时无限循环及无法添加DBHandler至onReceive的问题

Android SMS自动回复项目问题解决方案

问题1:接收SMS时陷入无限循环

原因

你的SmsListener会监听所有收到的短信,包括程序自身发送的回复短信。每次收到短信触发回复逻辑,回复的短信又会被自身的广播接收器捕获,进而再次触发回复,形成无限循环。

解决方案

在回复短信中添加专属标记,收到短信时先检查是否包含该标记,若包含则直接跳过处理,避免触发循环。同时,将回复逻辑移到后台服务中,避免在广播接收器中直接执行耗时操作。


问题2:无法在onReceive中使用DBHandler

原因

BroadcastReceiver的onReceive方法生命周期极短,且运行在主线程,直接在这里执行数据库查询、循环计算等操作,不仅容易引发ANR(应用无响应),还会因为生命周期限制导致DB操作不稳定。原代码中把DB操作放在MainActivity的Eye()方法里,通过启动Activity来处理的方式既不合理,又加重了循环问题。

解决方案

使用IntentService处理后台任务:广播接收器只负责接收短信并传递数据,实际的DB计算、短信回复逻辑全部交给IntentService完成,这样既符合Android组件生命周期规范,也能避免主线程阻塞。


修正后代码示例

1. 修正SmsListener.java(广播接收器)

public class SmsListener extends BroadcastReceiver {
    // 自动回复标记,用于过滤自身发送的短信
    private static final String AUTO_REPLY_TAG = "[系统自动回复]";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (!"android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction())) {
            return;
        }

        Bundle bundle = intent.getExtras();
        if (bundle == null) return;

        try {
            Object[] pdus = (Object[]) bundle.get("pdus");
            String format = bundle.getString("format");
            SmsMessage[] msgs = new SmsMessage[pdus.length];

            for (int i = 0; i < msgs.length; i++) {
                msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i], format);
                String msgFrom = msgs[i].getOriginatingAddress();
                String msgBody = msgs[i].getMessageBody();

                // 过滤自身发送的自动回复短信,终止循环
                if (msgBody.contains(AUTO_REPLY_TAG)) {
                    continue;
                }

                // 识别预约请求,启动后台服务处理
                if (msgBody.contains("Appt")) {
                    Intent serviceIntent = new Intent(context, SmsProcessingService.class);
                    serviceIntent.putExtra("sender", msgFrom);
                    serviceIntent.putExtra("content", msgBody);
                    ContextCompat.startForegroundService(context, serviceIntent);
                }
            }
        } catch (Exception e) {
            Log.d("SmsListener", "异常捕获:" + e.getMessage());
        }
    }
}

2. 新增SmsProcessingService.java(后台处理服务)

public class SmsProcessingService extends IntentService {
    private static final String AUTO_REPLY_TAG = "[系统自动回复]";

    public SmsProcessingService() {
        super("SmsProcessingService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent == null) return;

        String sender = intent.getStringExtra("sender");
        String content = intent.getStringExtra("content");

        // 初始化DBHandler,执行日期计算
        DBHandler dbHandler = new DBHandler(this);
        Calendar c1 = Calendar.getInstance();
        c1.add(Calendar.DAY_OF_MONTH, 1);
        SimpleDateFormat sdf = new SimpleDateFormat("MMM_dd_yyyy", Locale.getDefault());
        String dt = sdf.format(c1.getTime());
        int maxCount = 2;

        // 计算可用预约日期
        while (dbHandler.Count_Inv(sdf.format(c1.getTime()) + "_Eye", "Eye", dt, "Eye") > maxCount) {
            c1.add(Calendar.DAY_OF_MONTH, 1);
            dt = sdf.format(c1.getTime());
        }

        // 计算预约时段
        Long count = dbHandler.Count_Eye(sdf.format(c1.getTime()) + "_Eye", "Eye", dt);
        int slotIndex = count.intValue();
        double slot = 0;
        switch (slotIndex) {
            case 0: slot = 9.00; break;
            case 1: slot = 9.15; break;
            case 2: slot = 9.30; break;
            case 3: slot = 9.45; break;
            case 4: slot = 10.00; break;
            case 5: slot = 10.15; break;
        }

        // 添加预约记录到数据库
        dbHandler.addNewApptEye(sender, sdf.format(c1.getTime()) + "_Eye", dt, sdf.format(c1.getTime()), count);

        // 发送带标记的自动回复短信
        String replyMsg = AUTO_REPLY_TAG + "您的眼科预约时间:" + dt + " " + slot + "点";
        SmsManager smsManager = SmsManager.getDefault();
        smsManager.sendTextMessage(sender, null, replyMsg, null, null);

        // 可选:启动MainActivity展示结果
        Intent activityIntent = new Intent(this, MainActivity.class);
        activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(activityIntent);
    }
}

3. 修正MainActivity.java(移除自动执行逻辑)

public class MainActivity extends AppCompatActivity {
    EditText mobileno;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 移除自动执行的Eye(),改为手动触发(比如按钮点击)
    }

    // 保留手动预约逻辑,供界面触发使用
    public void manualBook(View view) {
        DBHandler dbHandler = new DBHandler(this);
        Calendar c1 = Calendar.getInstance();
        c1.add(Calendar.DAY_OF_MONTH, 1);
        SimpleDateFormat sdf = new SimpleDateFormat("MMM_dd_yyyy", Locale.getDefault());
        String dt = sdf.format(c1.getTime());
        int maxCount = 2;

        try {
            mobileno = findViewById(R.id.editText1);
            maxCount = Integer.parseInt(mobileno.getText().toString());
        } catch (Exception e) {
            e.printStackTrace();
        }

        while (dbHandler.Count_Inv(sdf.format(c1.getTime()) + "_Eye", "Eye", dt, "Eye") > maxCount) {
            c1.add(Calendar.DAY_OF_MONTH, 1);
            dt = sdf.format(c1.getTime());
        }

        Long count = dbHandler.Count_Eye(sdf.format(c1.getTime()) + "_Eye", "Eye", dt);
        int slotIndex = count.intValue();
        double slot = 0;
        switch (slotIndex) {
            case 0: slot = 9.00; break;
            case 1: slot = 9.15; break;
            case 2: slot = 9.30; break;
            case 3: slot = 9.45; break;
            case 4: slot = 10.00; break;
            case 5: slot = 10.15; break;
        }

        String phone = mobileno.getText().toString();
        dbHandler.addNewApptEye(phone, sdf.format(c1.getTime()) + "_Eye", dt, sdf.format(c1.getTime()), count);
        Toast.makeText(this, "预约成功:" + dt + " " + slot + "点", Toast.LENGTH_SHORT).show();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

额外注意事项

  1. 权限配置:在AndroidManifest.xml中添加必要权限并注册组件:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>

<receiver android:name=".SmsListener">
    <intent-filter android:priority="1000">
        <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
    </intent-filter>
</receiver>

<service android:name=".SmsProcessingService"/>
  1. 动态权限申请:Android 6.0及以上版本,需在代码中动态申请RECEIVE_SMS和SEND_SMS权限。
  2. 内存泄漏避免:移除原代码中使用静态变量传递短信内容的方式,改用Intent传递数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 20:25:23