Skip to content Skip to sidebar Skip to footer

Content Observer Onchange Method Called Twice After 1 Change In Cursor

I have an app in which I am hoping to send details in the android contact list to a remote server, so that the user can see his contacts online. To do this I want to notify the re

Solution 1:

i did a similar implementation and had set a ContentObserver over calendar's events URI. and i faced all the problems, you are facing now. So your question with my solutions/suggestions goes here....

1) Once I have set up a service that registers a ContentObserver on my Cursor, does that observer only exist within the service? I mean, if the service is killed, does the contentObserver continue to observe?

No, it will not observe the contents your contents over URI. but there is solution to this. you can create an always running service. This service will be created again as soon as it is dismissed due to some memory issue or other unexpected dismissal. It will always continue to run unless it is dismissed explicitly. To create such service override OnStartCommand(Intent intent, int flags, final int startId) in your Service class and return START_STICKY. Have a look at the code below.

publicintonStartCommand(Intent intent, int flags, finalint startId) {

    StringauthenticationKey= ((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: I suspect the answer is no, but I will ask anyway. Is there anyway of knowing which contact being updated is triggering the onchange method of my contentObserver? currently I have to compile the list of all teh contacts on the phone and send them off to my remote server, it would be so much easier to just send details of the contacts being updated.

You again guessed it right.:). the answer is No. There is no way to know specifically which contact has been updated. ContentObserver just provide an event to let you know that some change has been made to the data pointed by the uri. But i think you are handling the situation inefficiently, as you are compiling list of all the contacts and sending them back to the server. I would suggest you to maintain a list of contacts, which are successfully sent to server, in the local storage. And next time when you get a call in onChange() method of contentObserver you fetch all contacts from content_URI, compare them with previously stored list and send only updated contacts to server.

3: This is my main question, when I make a change to my Contact List the onChange method is being fired twice in quick succession. 1 change, 2 calls. Is there anyway of managing this?

Yes this happens, but i guess you are in wrong impression. In my case it used to fire randomly twice or thrice or even more times. so i had set a threshold_time interval. A time interval within which if ContentObserver is fired again, then i would not process it. I did something like this..

longlastTimeofCall=0L;
longlastTimeofUpdate=0L;
longthreshold_time=10000;

    /* (non-Javadoc)
     * @see android.database.ContentObserver#onChange(boolean)
     */@OverridepublicvoidonChange(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();
        }

    }  

Hope these suggestions/solutions would help.

Solution 2:

Consider how you register your observer. The second argument of registerContentObserver is boolean notifyForDescendents, you have set it to true. so you will be notified when either ContactsContract.Contacts.CONTENT_URI or any of its descandants uris were changed. It may be that some operation for contact with given id triggers notification both for the specific contact uri and global contacts uri - with second argument being true your observer observes both.

Another thing is that You can register content observer for specific contact id uri - ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId). This however has nothing to do with your issue but registering separate observer for every contact looks rather ugly ;)

Another suggestion: Maybe keep observer as final field not recreate it in onCreate (but only register it there).

publicclassContactServiceextendsService {

    private final ContentObserver contactsObserver = newContentObserver(null) {

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

            //your code here
        }
    };

    @Overridepublic IBinder onBind(Intent arg0) {
        returnnull;
    }

    @OverridepublicvoidonCreate() {

        super.onCreate();

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

    @OverridepublicvoidonDestroy() {

        getContentResolver().unregisterContentObserver(contactsObserver);

        super.onDestroy();
    }
}

Solution 3:

To come right to your nr. 3: How much time is in between the two calls to your observer? I think your observer gets called twice because of the contacts sync, which also updates the database. Ie. first time is your actual update, second time is when the sync finished and registers its sync values in the same contact row.

Could you turn off sync and see if it still gets called twice?

Solution 4:

you may have two or more instances of ContactService which all of them are registed the same ContactsContract.Contacts.CONTENT_URI.

Solution 5:

Faced the same problem in my own code and found out that I was calling registerContentObserver() twice. Although it was for the exact same URI and within the same class my onChange(boolean selfChange) method was called twice as a result.

Post a Comment for "Content Observer Onchange Method Called Twice After 1 Change In Cursor"