Sms ContentObserver onChange()会多次触发

时间:2012-02-02 19:16:24

标签: java android contentobserver

我知道这个问题已被多次询问,但没有人能够从我所看到的那里得到一个有效的答案。

我正在使用应用拦截短信,并根据发送信息#弹出自定义提醒。我使用广播接收器可以很好地工作,但是如果用户安装了goSms,则永远不会调用onReceive()方法,因为goSms在到达我的应用之前就会中止它。

为了解决这个问题,我在content://sms/尝试内容观察者 它的工作正常,但onChange()被调用两次,参数完全相同。我曾尝试检查时间戳,但它们是相同的,就像我设置的类型和其他所有参数一样。

从我所看到的情况来看,这是一个常见的问题,但不是我见过的任何一个问题。

    @Override
public void onChange(boolean selfChange) {
    super.onChange(selfChange);
    querySMS();
}

protected void querySMS() {
    Cursor cur = getContentResolver().query(u, null, null, null, null);
    cur.moveToNext(); // this will make it point to the first record, which is the last SMS sent
    String type = cur.getString(cur.getColumnIndex("type"));
    String body = cur.getString(cur.getColumnIndex("body")); //content of sms
    String add = cur.getString(cur.getColumnIndex("address")); //phone num
    if (type.equals("1")) {
        if (add.equals(Test.SENDER)) {              
            String[] bodys = body.split(" ", 7);
            if (bodys[0].equals("test")) {
                test = true;
            }
            cat = bodys[1];
            level = bodys[2];
            urgency = bodys[3];
            certainty = bodys[4];
            carrier = bodys[5];
            message = bodys[6];
            final Intent intent = new Intent(context, AlertActivity.class);
            Bundle b = new Bundle();
            b.putString("title", cat);
            b.putString("certainty", certainty);
            b.putString("urgency", urgency);
            b.putString("level", level);
            b.putString("message", message);
            b.putBoolean("test", test);
            intent.putExtras(b);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
            carrierName = manager.getNetworkOperatorName();
            if (carrierName.replaceAll(" ", "").equals(carrier)) {

                context.startActivity(intent);
            } else {
                //testing
                Toast.makeText(context, carrierName.replaceAll(" ", ""), Toast.LENGTH_LONG).show();
            }
        }
    }
}

由于onChange()被解雇两次,我也会收到两个警报。我无法为我的生活找到解决方法。

4 个答案:

答案 0 :(得分:4)

如果两者相同:
存储收到的每条消息 将它与之前收到的消息进行比较 如果没有找到,请处理
如果找到,请丢弃该消息

存储的消息的生命周期应该是无穷小的,5个消息的小循环缓冲区应该没问题。

答案 1 :(得分:4)

这是我的代码,它对我来说很好用

public class SmsObserver extends ContentObserver {  
    private Context context;
    private static int initialPos;
    private static final String TAG = "SMSContentObserver";
    private static final Uri uriSMS = Uri.parse("content://sms/sent");

    public SmsObserver(Handler handler, Context ctx) {
        super(handler);
        context = ctx;
        initialPos = getLastMsgId();

    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        queryLastSentSMS();
    }

    public int getLastMsgId() {

        Cursor cur = context.getContentResolver().query(uriSMS, null, null, null, null);
        cur.moveToFirst();
        int lastMsgId = cur.getInt(cur.getColumnIndex("_id"));
        Log.i(TAG, "Last sent message id: " + String.valueOf(lastMsgId));
        return lastMsgId;
    }

    protected void queryLastSentSMS() {

        new Thread(new Runnable() {

            @Override
            public void run() {
                Cursor cur =
                    context.getContentResolver().query(uriSMS, null, null, null, null);

                if (cur.moveToNext()) {


                    try {
                        if (initialPos != getLastMsgId()) {
                            // Here you get the last sms. Do what you want.
                            String receiver = cur.getString(cur.getColumnIndex("address"));
                           System.out.println(" Receiver Ph no :"+receiver);


                            // Then, set initialPos to the current position.
                            initialPos = getLastMsgId(); 
                        }
                    } catch (Exception e) {
                        // Treat exception here
                    }
                }
                cur.close();
            }
        }).start();

    }

}//End of class SmsObserver

答案 2 :(得分:3)

您可以保存上一封邮件的ID,并将其与curonChange返回的邮件的ID进行比较。如果ID相同,那么你可以简单地忽略该消息。

// might contain mistakes, but you'll get the idea:
protected void querySMS() {
    Cursor cur = getContentResolver().query(u, null, null, null, null);
    cur.moveToNext(); 
    if (lastId == cur.getLong(cur.getColumnIndex("_id")))
        return;
    lastId = cur.getLong(cur.getColumnIndex("_id"));
    ... //continue as it was
}

然而 - 如果用户选择此选项(接收设置 - 禁用其他消息通知),GO短信仅阻止其他应用接收广播 - 所以如果用户不希望其他应用打扰他 - 我认为不这样做是个好主意。

答案 3 :(得分:0)

我只是使用SharedPreference来记录最后的短信息(例如:id\type ...)。如果它是相同的,我会return