短信-彩信 Class 意外结果

SMS-MMS Class Unexpected Results

我在使用此 sms-mms class 时遇到了一些问题,问题是 returns 是预期数据的 6 倍。它显示之前的 3 条消息,然后显示 3 条当前的消息,我只需要 1 条当前的消息,但不确定如何以 6 结束...像这样;

V/Debug: 观察者开始

V/Debug: 收到短信

V/Debug:发件人:+15555551212

V/Debug:类型:1

V/Debug:时间:2 月 9 日星期五 10:01:53 2018 年美国东部时间

V/Debug:正文:一些短信...

重建Class来源

public class MessageService extends Service {

private static final String VER = "1.1.10";
private static final String TAG = "ClassMessageService";

private ContentResolver contentResolver;

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {

    Log.v(TAG, "Message capturing service version: " + VER);
    Log.v(TAG, "Message capturing service created " + ReturnCurrentDateTime());

}

public int onStartCommand(Intent intent, int flags, int startId) {

    registerObserver();

    return START_STICKY;

}

public void registerObserver() {

    contentResolver = getContentResolver();
    contentResolver.registerContentObserver(Uri.parse("content://mms-sms"), true, new MessageObserver(new Handler()));

}

public String ReturnCurrentDateTime() {

    Date datetime = new Date();
    datetime.getTime();

    return datetime.toString();

}

class MessageObserver extends ContentObserver {

    private final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);

    private static final int SMS_MESSAGE = 0;
    private static final int MMS_MESSAGE = 1;

    //static {
    //    MATCHER.addURI("sms", "#", SMS_MESSAGE);
    //    MATCHER.addURI("mms", "#", MMS_MESSAGE);
    //}

    public MessageObserver(Handler handler) {
        super(handler);
        Log.v(TAG, "MessageObserver...");
        MATCHER.addURI("sms", "#", SMS_MESSAGE);
        MATCHER.addURI("mms", "#", MMS_MESSAGE);
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {

        super.onChange(selfChange, uri);

        switch (MATCHER.match(uri)) {
            case SMS_MESSAGE:

                Cursor cursor = contentResolver.query(uri, null, null, null, null);
                cursor.moveToNext();

                String msg_id;
                String phone;
                String dateVal;
                String body;
                Date date;

                msg_id = cursor.getString(cursor.getColumnIndex("_id"));
                phone = cursor.getString(cursor.getColumnIndex("address"));
                dateVal = cursor.getString(cursor.getColumnIndex("date"));
                body = cursor.getString(cursor.getColumnIndex("body"));

                date = new Date(Long.valueOf(dateVal));

                Log.v(TAG, "SMS: " + phone + " " + body + " " + msg_id + " " + date);

                break;

            case MMS_MESSAGE:

                Cursor mcursor = contentResolver.query(uri, null, null, null, null);
                mcursor.moveToNext();

                String mmsg_id;
                String mphone;
                String mdateVal;
                String mbody;
                Date mdate;

                mmsg_id = mcursor.getString(mcursor.getColumnIndex("_id"));
                mphone = mcursor.getString(mcursor.getColumnIndex("address"));
                mdateVal = mcursor.getString(mcursor.getColumnIndex("date"));
                mbody = mcursor.getString(mcursor.getColumnIndex("body"));

                mdate = new Date(Long.valueOf(mdateVal));

                Log.v(TAG, "SMS: " + mphone + " " + mbody + " " + mmsg_id + " " + mdate);

                break;

            default:

        }
    }

}

}

content://mms-sms URI 上注册您的 ContentObserver – 大概是 true 用于后代 – 通常会给您带来很多冗余和不相关的更改通知,并且您的观察者正在响应所有这些。

标准 SmsProviderMmsProvider 都会向多个 URI 发送更改通知。例如,标准 SmsProvider 调度到特定的 content://sms/# URI(其中 # 是消息 ID),以及一般的 content://mms-sms URI,content://mms-sms/conversation 网址。您的观察者正在处理的每条消息至少有两个通知。

此外,MmsSmsProvider——一般处理线程(对话),而不是单独的消息——可以在修改线程时在 content://mms-sms 上触发更改通知;例如,更新其摘要,将其标记为已读等。如果您真的只想跟踪消息发送或接收,这些更改是无关紧要的,但您的 Observer 每次仍在抓取和处理最新消息。

我推荐的解决方案分为两部分:更改您的 ContentObserver 以覆盖 onChange(boolean, Uri) 方法,并分别在 content://smscontent://mms URI 上注册.

首先,ContentObserver 自 API 级别 16 以来有一个带有 Uri 参数的 onChange() 方法。即:

@Override
public void onChange(boolean selfChange, Uri uri) {
    ...
}

独自一人,对您的观察者的这种更改不会有太大帮助,因为您到达那里的 Uri 可能是通用 URI – 例如,content://mms-smscontent://mms-sms/conversation –没有其他身份信息。

第二个建议解决了这个问题——分别在 content://smscontent://mms 上注册,而不是在 content://mms-sms 上注册。即:

getContentResolver().registerContentObserver(Uri.parse("content://sms"), ...);
getContentResolver().registerContentObserver(Uri.parse("content://mms"), ...);

这样做会阻止您的观察者在 content://mms-sms URI 上收到不相关的通知,并且您应该在 onChange() 中获得更具体的 Uri,形式为 content://sms/#content://mms/#,其中 # 是消息的 ID,long。此 Uri 可用于检查消息是 SMS 还是 MMS,以及它是否是您感兴趣的更改,作为不相关更改的 URI——例如,对 SMS 的更改 raw table – 不应匹配这些表格。

如果对两个已注册的 Uri 使用单个 Observer*,则可以使用 UriMatcher.例如:

public class MessageObserver extends ContentObserver {

    private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
    private static final int SMS_MESSAGE = 0;
    private static final int MMS_MESSAGE = 1;
    static {
        MATCHER.addURI("sms", "#", SMS_MESSAGE);
        MATCHER.addURI("mms", "#", MMS_MESSAGE);
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        switch (MATCHER.match(uri)) {
            case SMS_MESSAGE:

                break;

            case MMS_MESSAGE:

                break;

            default:

        }
    }

    ...
}

此外,您可以直接使用特定的 Uri 查询来获取单个消息的详细信息,而不是查询一般的 content://smscontent://mms URI,然后获取每个任一提供者中的消息,仅检查第一个。

最后,您可能已经注意到我在这里限定了许多语句,如 "should"、"likely" 等。这些提供程序的实现可能与预期的。我建议您尽可能彻底地测试您的 Observer。


* 据我所知,为多个 URI 注册单个 Observer 实例没有问题,我的测试也从未出现过任何问题。但是,您当然可以为 SMS 和 MMS 实现单独的 ContentObserver,并且 UriMatcher 仍然可以用于过滤不相关的 URI。