Content Observer onChange метод, вызываемый дважды после 1 изменения курсора

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

Я установил ContentObserver в "ContactsContract.Contacts.CONTENT_URI" из службы, которая запускается при загрузке телефона.

У меня есть несколько quiestions, первые 2 являются случайными, третье - моя главная проблема.

1: Как только я настроил службу, которая регистрирует ContentObserver на моем курсоре, этот наблюдатель существует только внутри службы? Я имею в виду, что если служба убита, сохраняется ли контент-сервер?

2: Я подозреваю, что ответ отрицательный, но я все равно спрошу. Есть ли в любом случае знать, какой контакт обновляется, запускает метод onchange моего contentObserver? в настоящее время мне приходится составлять список всех контактов на телефоне и отправлять их на мой удаленный сервер, было бы гораздо проще просто отправлять детали обновляемых контактов.

3: Это мой главный вопрос, когда я вношу изменения в свой Список контактов, метод onChange запускается дважды в быстрой последовательности. 1 изменение, 2 вызова. Есть ли способ управления этим?

    public class ContactService extends Service {

    JSONArray contactList;

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

    @Override
    public void onCreate() {
        Log.i("C2DM","content observers initialised");
        super.onCreate();



        //Call Log Content Provider observer

        MyContentContactsObserver contactsObserver = new MyContentContactsObserver();
        ContactService.this.getContentResolver().registerContentObserver (ContactsContract.Contacts.CONTENT_URI, true, contactsObserver);   

    }

    private class MyContentContactsObserver extends ContentObserver {

        public MyContentContactsObserver() {
            super(null);
        }

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);    
            Log.i("LOG","detected change in contacts: "+selfChange);
        }
    }
}

REsults в 2 быстрых строках в моем logCat:

 detected change in contacts: false 
 detected change in contacts: false

Ответы

Ответ 1

Я сделал аналогичную реализацию и установил ContentObserver по событиям календаря URI. и я столкнулся со всеми проблемами, с которыми вы сейчас сталкиваетесь. Итак, ваш вопрос с моими решениями/предложениями идет здесь....

1) Как только я настроил службу, которая регистрирует ContentObserver, мой Курсор,     этот наблюдатель существует только внутри службы? Я имею в виду, что если служба убита,     сохраняется ли контент-сервер?

Нет, он не будет соблюдать содержимое вашего содержимого по URI. но есть решение этого. вы можете создать всегда запущенный сервис. Эта услуга будет создана снова, как только она будет уволена из-за некоторой проблемы с памятью или другого неожиданного увольнения. Он всегда будет продолжать работать, если он явно не будет уволен. Чтобы создать такой сервис, переопределите OnStartCommand(Intent intent, int flags, final int startId) в своем классе Service и верните START_STICKY. Посмотрите на код ниже.

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

    String authenticationKey = ((MainApplication) getApplicationContext()).getDbConnector().getUserAuthDefault() ;
    // if user is not registered yet, stop this service, it may be called from boot reciever.
    if(authenticationKey == null){
        stopSelf();
    }

    // restart, if we get killed.
    return START_STICKY;
}  

.

2: Я подозреваю, что ответ отрицательный, но я все равно спрошу. Там в любом случае зная, что     обновленный контакт запускает метод onchange моего contentObserver?     в настоящее время мне приходится составлять список всех контактов на телефоне и отправлять их на     мой удаленный сервер, было бы намного проще просто отправлять детали обновляемых контактов.

Вы снова догадались, что это правильно.:). ответ №. Невозможно точно узнать, какой контакт был обновлен. ContentObserver просто предоставляет событие, дающее вам знать, что некоторые изменения были внесены в данные, указанные uri. Но я думаю, что вы справляетесь с ситуацией неэффективно, поскольку вы составляете список всех контактов и отправляете их обратно на сервер.
Я предлагаю вам сохранить список контактов, которые успешно отправлены на сервер, в локальном хранилище. И в следующий раз, когда вы получите вызов в onChange() методе ContentObserver, вы получите все contacts из content_URI, сравните их с ранее сохраненным списком и отправьте только обновленные контакты на сервер.

3: Это мой главный вопрос, когда я вношу изменения в свой Список контактов метод onChange     дважды выстреливается быстро. 1 изменение, 2 вызова. Есть ли способ управления     это?

Да, это происходит, но я думаю, что вы ошибаетесь. В моем случае он срабатывал случайным образом дважды или трижды или даже больше раз. поэтому я установил интервал порогового значения. Временной интервал, в течение которого if ContentObserver запускается снова, тогда я не буду его обрабатывать. Я сделал что-то вроде этого.

long lastTimeofCall = 0L;
long lastTimeofUpdate = 0L;
long threshold_time = 10000;

    /* (non-Javadoc)
     * @see android.database.ContentObserver#onChange(boolean)
     */
    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);

        Log.d("content service", "on change called");

        lastTimeofCall = System.currentTimeMillis();

        if(lastTimeofCall - lastTimeofUpdate > threshold_time){

         //write your code to find updated contacts here

          lastTimeofUpdate = System.currentTimeMillis();
        }

    }  

Надеемся, что эти предложения/решения помогут.

Ответ 2

Посмотрите, как вы регистрируете своего наблюдателя. Второй аргумент registerContentObserver равен boolean notifyForDescendents, вы установили его в true. поэтому вы будете уведомлены, когда были изменены либо ContactsContract.Contacts.CONTENT_URI, либо какой-либо из его descandants uris. Возможно, что некоторая операция для контакта с указанными идентификаторами запускает уведомление как для конкретного контакта uri, так и для глобальных контактов uri - со вторым аргументом true ваш наблюдатель замечает оба.

Другое дело, что вы можете регистрировать контент-наблюдателя для определенного идентификатора контакта uri - ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId). Это, однако, не имеет ничего общего с вашей проблемой, но регистрация отдельного наблюдателя для каждого контакта выглядит довольно уродливо;)

Другое предложение: возможно, чтобы наблюдатель был в качестве конечного поля, не воссоздавайте его в onCreate (но регистрируйте его там).

public class ContactService extends Service {

    private final ContentObserver contactsObserver = new ContentObserver(null) {

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);    
            Log.i("LOG","detected change in contacts: "+selfChange);

            //your code here
        }
    };

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

    @Override
    public void onCreate() {

        super.onCreate();

        getContentResolver().registerContentObserver(
                ContactsContract.Contacts.CONTENT_URI, true, contactsObserver);   
    }

    @Override
    public void onDestroy() {

        getContentResolver().unregisterContentObserver(contactsObserver);

        super.onDestroy();
    }
}

Ответ 3

Приходите прямо к своему nr. 3: Сколько времени между двумя вызовами вашего наблюдателя? Я думаю, что ваш наблюдатель дважды вызывается из-за синхронизации контактов, которая также обновляет базу данных. То есть. первый раз - ваше фактическое обновление, второй раз - когда синхронизация завершена и регистрирует значения синхронизации в той же строке контактов.

Не могли бы вы отключить синхронизацию и посмотреть, не вызвана ли она еще дважды?

Ответ 4

у вас могут быть два или более экземпляра ContactService, для которых у всех из них есть те же ContactsContract.Contacts.CONTENT_URI.

Ответ 5

Столкнувшись с той же проблемой в моем собственном коде, выяснилось, что я дважды вызывал registerContentObserver(). Хотя это было для того же самого URI и внутри того же класса, мой метод onChange (boolean selfChange) был вызван дважды в результате.