Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Sms ContentObserver onChange()多次激发_Java_Android_Contentobserver - Fatal编程技术网

Java Sms ContentObserver onChange()多次激发

Java Sms ContentObserver onChange()多次激发,java,android,contentobserver,Java,Android,Contentobserver,我知道这个问题已经被问了很多次了,但从我所看到的情况来看,没有人能给出有效的答案 我正在开发一个截获短信的应用程序,根据发送时间,会弹出一个自定义警报。我让它与广播接收器完美配合,但是如果用户安装了GOSM,则不会调用onReceive()方法,因为GOSM会在它到达我的应用程序之前中止它 为了解决这个问题,我尝试在content://sms/ 它工作正常,但是调用了两次onChange(),参数完全相同。我试着检查时间戳,但它们是一样的,我设置的类型和其他参数也是一样的 从我所看到的,这是一个

我知道这个问题已经被问了很多次了,但从我所看到的情况来看,没有人能给出有效的答案

我正在开发一个截获短信的应用程序,根据发送时间,会弹出一个自定义警报。我让它与广播接收器完美配合,但是如果用户安装了GOSM,则不会调用
onReceive()
方法,因为GOSM会在它到达我的应用程序之前中止它

为了解决这个问题,我尝试在
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()
被触发了两次,我也收到了两个警报。我一辈子都想不出解决这个问题的办法。

如果两者相同:
存储接收到的每条消息
将其与以前接收的消息进行比较
如果未找到,则处理
如果找到,则丢弃该消息


存储的消息的寿命应该是无限小的,一个5条消息的小循环缓冲区就可以了。

您可以保存最后一条消息的id,并将其与
onChange
中的
cur
返回的消息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 SMS只会阻止其他应用程序接收广播-因此,如果用户不希望其他应用程序打扰他-我认为最好不要这样做。

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

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

我只是使用SharedReference注释最后的SMS信息(比如:
id\type
…)。如果是相同的,我将
返回

指向其他(不完整)答案的链接将很有帮助。尽管消息只收到一次。它不会再来两次。tbh,我甚至不知道第二个
onChange
是从什么触发的。啊。把你的想法和我的想法结合起来,我成功了。我想我第一次读的时候误解了你的意思。我创建了一个静态的
arrayList
,并使用它进行检查。
if(!ids.contains(id)){ids.add(id);context.startActivity(intent);}
Im使用的应用程序永远都不应该被忽略。它可以预先安装在设备上,并且完全优先于手机上当前运行的任何其他设备。我做了一些与此类似的事情,如果你看下面答案的评论,你会看到。你明白,你发布的代码片段在应用程序中使用之前应该有很长很长的路要走,是不是?哦,是的,当然。我才刚开始这个项目。还有很长的路要走