Android не удалось установить смс-обозреватель

Я пытаюсь написать приложение службы Android, которое перехватывает исходящие SMS-сообщения (из-за недоступности службы), чтобы сохранить их и попытаться отправить их повторно, как только телефонная служба вернется. Я почти заставил это работать, но у меня есть проблема, которую не так просто объяснить, но я попытаюсь, надеюсь, вы понимаете: я установил ContentObserver в URI content://sms, даже если то, что мне интересно on это content://sms/failure, потому что, если я установлю его на этот последний URI, метод onChange не сработает, и я не знаю, почему. При условии, что успешно отправленные и полученные сообщения меня не беспокоят, поскольку в методе onChange в наблюдателе я читаю только содержимое в content://sms/failed, вот настоящая проблема: onChange срабатывает также при событиях DELETE, из конечно, которые происходят, например, в момент успешной отправки ранее неудачного сообщения. Это плохо для моего приложения, потому что, если я не могу различить событие удаления и событие добавления, я не знаю, нужно ли мне добавлять первое sms в очереди сообщений с ошибками в список «повторно отправить». Итак, мой вопрос: есть ли способ различать события удаления и добавления с помощью наблюдателя контента?

PS: Было бы неплохо понять, почему ContentObserver на content://sms/failed не работает.

PPS: у меня есть еще одна небольшая проблема: я повторно отправляю сообщения с помощью SmsManager, который отлично работает, единственная проблема в том, что я могу установить только номер получателя и тело сообщения, но не идентификатор сообщения, поэтому, когда я повторно отправить смс, система думает, что это просто новое смс, а не повторно отправленное старое (поэтому старые неудачные сообщения остаются в очереди и не удаляются системой).


person Drakem    schedule 13.10.2015    source источник
comment
Боже!.. МОИ ГЛАЗА!!! TL;DR Пожалуйста, сделайте более читабельным.   -  person JoxTraex    schedule 13.10.2015


Ответы (1)


... есть ли способ различать события удаления и добавления с помощью наблюдателя контента?

Запросите URI, переданный в метод onChange(). Если Cursor пуст, т. е. getCount() возвращает 0, то это было удаление. Например:

public void onChange(boolean selfChange, Uri uri)
{
    boolean deletion = false;

    Cursor cursor = getContentResolver().query(uri, null, null,
                                               null, null);

    if(cursor != null)
        deletion = cursor.getCount() == 0;
    else
        return;

    ...
}

Было бы неплохо понять, почему ContentObserver на content://sms/failed не работает.

Именно так реализован SMS ContentProvider. Вы не можете получить ничего более конкретного, чем content://sms.

У меня есть еще одна небольшая проблема...

Идентификатор сообщения назначается ContentProvider, и самое быстрое, что ваше приложение может узнать его значение, находится в методе onChange(). У вас нет контроля над назначением идентификаторов, поэтому вашему приложению придется самостоятельно отслеживать идентификаторы ошибочных сообщений и удалять соответствующее сообщение после успешной отправки.

person Mike M.    schedule 13.10.2015
comment
Для первого ответа: неверно, если в результате запроса более 1 сообщения. Всякий раз, когда перехватывается ошибочное сообщение, я читаю только первый результат запроса, поскольку для каждого нового события ошибочного сообщения генерируется новый вызов onChange, поэтому нет необходимости читать более одной записи. ОК для второго ответа. Что касается последнего, я уже знаю, что могу получить идентификатор SMS в методе onChange, и я действительно это делаю. Я не знаю, как удалить SMS из content://sms/failed. - person Drakem; 13.10.2015
comment
1) Вы не должны получать более одного сообщения в результате вашего запроса. 2) Это то, что ваше приложение должно будет отслеживать - идентификаторы/URI неудачных отправок. После успешной отправки delete() сохраненный URI. - person Mike M.; 13.10.2015
comment
Теперь я понимаю, что, возможно, я был не слишком ясен в первой части своего ответа. Я думаю, что вы можете использовать неправильный запрос, поэтому я добавил пример. Я не могу быть более конкретным в последней части моего ответа, не зная немного больше о том, как ваше приложение должно функционировать. - person Mike M.; 13.10.2015
comment
Я использовал тот же запрос, что и вы. Проблема в том, что я уже проверяю cur.getCount() == 0, и это НЕ верно, когда происходит удаление. Выполняя отладку, я вижу, что значение cur.getCount() равно кардинальности содержимого://SMS/failed. Так, например, если в системе есть ошибочные сообщения (я имею в виду систему Android), ДО того, как я установлю свое приложение, cur.getCount() всегда будет учитывать эти сообщения. Сейчас я не на своем компьютере, как только я доберусь до него, я опубликую код, если он все еще нужен. - person Drakem; 13.10.2015
comment
Да, все они имеют назначенный _id. Но моя проблема НЕ в том, как выполнить удаление повторно отправленных сообщений через _id, реальная проблема заключается в том, что когда происходит удаление (я имею в виду ЛЮБОЕ удаление, например, одно, которое пользователь вручную делает в приложении смс), метод onChange запускается без возможности понять, был ли этот звонок удалением или новой неудачной исходящей смс. В любом случае, вот код моего onChange: - person Drakem; 13.10.2015
comment
Да, все они имеют назначенный _id. Но моя проблема НЕ в том, как выполнить удаление повторно отправленных сообщений через _id, реальная проблема заключается в том, что когда происходит удаление (я имею в виду ЛЮБОЕ удаление, например, одно, которое пользователь вручную делает в приложении смс), метод onChange срабатывает без возможности понять, был ли этот звонок удалением или новым неудачным исходящим смс. - person Drakem; 13.10.2015
comment
Так случается, что, например, если в базе данных о неудачных смс (давайте представим ее в виде стека) есть старая ошибочная смс, сгенерированная до того, как мое приложение было установлено, и еще одно ошибочное сообщение поверх нее, сгенерированное во время работы моего приложения. , в тот момент, когда я удаляю сообщение сверху, срабатывает onChange, считывает базу данных, находит старое сообщение и вставляет его в список smsToResend. - person Drakem; 13.10.2015
comment
Во всяком случае, вот код моего onChange: pastebin.com/rgwAYh7G (извините, я не знаю, как создайте поле кода) Переменная lastSms содержит последнее неудачное чтение sms из базы данных, поэтому, если onChange запускается полученным sms или успешно отправленным sms, он не повторно вставляет sms в список smsToSend. writeToDatabase — это просто метод записи этого списка в файл. - person Drakem; 13.10.2015
comment
Посмотрите еще раз на свой метод onChange(). Ваш пример не похож на мой. Есть два метода onChange(). Вам нужен тот, который проходит в URI, как в моем примере. Это URI, который вы должны запрашивать, а не ваш uriSMSURI. Этот URI должен быть для одного сообщения. - person Mike M.; 13.10.2015
comment
Хорошо, теперь я понял, как работает onChange. Спасибо. Теперь почти все работает, но у меня есть 2 странные проблемы в этом фрагменте кода: pastebin.com/d8XBQG0v getColumnIndex возвращает индекс -1 в первой проблеме, что действительно странно, поскольку мой getCount() не равен 0, а столбец типа находится в списке выбора. Вторая проблема заключается в том, что метод удаления возвращает 0 (строка не удалена), что также очень странно, поскольку смс с указанным идентификатором ДЕЙСТВИТЕЛЬНО существует с тех пор, как я получил его в первом запросе (getCount() != 0) - person Drakem; 14.10.2015
comment
1) Вам нужно переместить курсор на строку, прежде чем пытаться получить значение. Добавьте cur.moveToFirst() перед отмеченной строкой. 2) Должно быть Uri.parse("content://sms/" + sms.getId()). - person Mike M.; 14.10.2015
comment
Хорошо, отсутствие moveToFirst() (или moveToNext()) было глупой ошибкой... но у меня все еще есть проблемы с удалением. Я уже использовал Uri.parse(content://sms/ + sms.getId()) (я отредактировал свой предыдущий комментарий, не знаю, читали ли вы старую версию). Теперь это мой код, удаление не работает: pastebin.com/39iR3h78 - person Drakem; 15.10.2015