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) был вызван дважды в результате.