内容观察器onChange方法在光标改变1之后调用两次

我有一个应用程序,我希望在Android联系人列表中发送详细信息到远程服务器,以便用户可以在线查看他的联系人。 要做到这一点,我想通知远程服务器在手机上所做的任何更改联系人列表。

我已经从电话启动时启动的服务在“ContactsContract.Contacts.CONTENT_URI”上设置了一个ContentObserver。

我有一些困扰,前两个是偶然的,第三个是我主要关心的。

1:一旦我build立了在我的光标上注册一个ContentObserver的服务,那么这个观察者是否只存在于服务中呢? 我的意思是,如果服务被杀死,contentObserver是否继续观察?

2:我怀疑答案是否定的,但我仍然会问。 有没有办法知道哪个联系人正在更新触发我的contentObserver的onchange方法? 目前我必须编译手机上的所有联系人列表,并将它们发送到我的远程服务器,只需发送正在更新的联系人的详细信息就会简单多了。

3:这是我的主要问题,当我更改我的联系人列表时,onChange方法连续两次被触发。 1次更换,2次电话。 有没有pipe理这个?

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); } } } 

在我的logCat中快速结束两行:

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

Solutions Collecting From Web of "内容观察器onChange方法在光标改变1之后调用两次"

我做了一个类似的实现,并在日历的事件URI设置了一个ContentObserver 。 我面临所有的问题,你现在面临着。 所以你的问题与我的解决scheme/build议在这里….

1)一旦我build立了一个在我的光标上注册一个ContentObserver的服务,这个观察者是否只存在于服务中? 我的意思是,如果服务被杀害,contentObserver继续观察?

不,它不会通过URI观察您的内容。 但是有这个解决办法。 您可以创build一个始终运行的服务。 一旦由于内存问题或其他意外的解雇而被解雇,该服务将被重新创build。 除非明确否认,否则它将继续运行。 要在您的Service类中创build此类服务,请覆盖OnStartCommand(Intent intent, int flags, final int startId)并返回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:我怀疑答案是否定的,但我仍然会问。 有没有办法知道哪个联系人正在更新触发我的contentObserver的onchange方法? 目前我必须编译手机上的所有联系人列表,并将它们发送到我的远程服务器,只需发送正在更新的联系人的详细信息就会简单多了。

你再次猜对了。 答案是不。
没有办法知道具体哪个联系人已经更新。 ContentObserver只是提供一个事件,让你知道对uri指向的数据做了一些改变。 但是我认为你正在低效地处理这种情况,因为你正在编译所有联系人列表并将它们发送回服务器。
我build议你在本地存储器中维护一个成功发送到服务器的联系人列表。 下一次当你在contentObserver onChange()方法中调用时,你可以从content_URI获取所有的contacts ,将它们与以前存储的列表进行比较,并只发送更新后的联系人给服务器。

3:这是我的主要问题,当我更改我的联系人列表时,onChange方法正在快速连续两次被触发。 1次更换,2次电话。 有没有pipe理这个?

是的,但是我想你是错误的印象。 在我的情况下,它会随机发生两次或三次甚至更多次。 所以我设置了一个threshold_time间隔。 一个时间间隔,如果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(); } } 

希望这些build议/解决scheme会有帮助。

考虑你如何注册你的观察者。 registerContentObserver的第二个参数是boolean notifyForDescendents ,您已将其设置为true 。 所以当ContactsContract.Contacts.CONTENT_URI或其任何descandants uris被更改时,您将会收到通知。 这可能是一些与给定的ID联系的操作触发通知特定的联系人uri和全球联系人uri – 第二个参数是true你的观察员观察两个。

另一件事是,你可以注册内容观察员的具体联系人ID uri – ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId) 。 这与你的问题无关,但为每个联系人注册单独的观察员看起来相当丑陋;)

另一个build议:也许保持观察者作为最后的领域不重新创buildonCreate(但只有在那里注册)。

 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(); } } 

来到你的nr。 3:两次打电话给观察者多less时间? 我认为你的观察者被调用两次,因为联系人同步,这也更新数据库。 IE浏览器。 第一次是你的实际更新,第二次是当同步完成,并注册其同步值在同一联系人行。

你可以closures同步,看看它是否仍然被调用两次?

您可能有两个或更多的ContactService实例,它们都被注册为相同的ContactsContract.Contacts.CONTENT_URI。

面对同样的问题,在我自己的代码,发现我正在调用registerContentObserver()两次。 虽然它是完全相同的URI,并在同一类中,我的onChange(boolean selfChange)方法被调用两次作为结果。