2012-04-16 9 views
14

Ho un'app in cui spero di inviare i dettagli nell'elenco dei contatti Android a un server remoto, in modo che l'utente possa vedere i suoi contatti online. Per fare ciò, desidero notificare al server remoto eventuali modifiche apportate al telefono all'elenco dei contatti.Metodo Observer onChange chiamato due volte dopo 1 modifica nel cursore

Ho impostato un ContentObserver su "ContactsContract.Contacts.CONTENT_URI" da un servizio che viene avviato all'avvio del telefono.

Ho un certo numero di quiestions, i primi 2 sono incidentali, la terza è la mia principale preoccupazione.

1: Una volta che ho creato un servizio che registra un ContentObserver sul mio cursore, fa quel osservatore esiste solo all'interno del servizio? Voglio dire, se il servizio viene ucciso, il ContentObserver continua ad osservare?

2: Ho il sospetto che la risposta è no, ma io chiederò comunque. Esiste comunque la possibilità di sapere quale contatto viene aggiornato sta attivando il metodo onchange del mio contentObserver? attualmente devo compilare l'elenco di tutti i contatti sul telefono e inviarli al mio server remoto, sarebbe molto più semplice inviare semplicemente i dettagli dei contatti che sono stati aggiornati.

3: Questa è la mia domanda principale, quando faccio un cambiamento alla mia lista dei contatti del metodo onChange viene attivato due volte in rapida successione. 1 cambio, 2 chiamate. Esiste comunque la gestione di questo?

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

risultati in 2 linee veloci nella mia Logcat:

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

risposta

29

ho fatto un'implementazione simile e aveva fissato un ContentObserver sugli eventi del calendario URI. e ho affrontato tutti i problemi, ora stai affrontando. Quindi la tua domanda con le mie soluzioni/proposte va qui ....

1) Una volta che ho creato un servizio che registra un ContentObserver sul mio cursore, vuol osservatore esistono solo all'interno del servizio? Voglio dire, se il servizio viene ucciso, il ContentObserver continua a osservare?

No, non osserverà il contenuto con l'URI. ma c'è una soluzione a questo. puoi creare un servizio sempre in esecuzione. Questo servizio verrà creato di nuovo non appena viene rimosso a causa di alcuni problemi di memoria o altri licenziamenti imprevisti. Continuerà sempre a funzionare a meno che non venga respinto esplicitamente. Per creare tale servizio, eseguire l'override OnStartCommand(Intent intent, int flags, final int startId) nella classe Servizio e restituire START_STICKY. Dai un'occhiata al codice qui sotto.

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: Sospetto che la risposta sia no, ma lo chiederò comunque. C'è comunque di sapere quale contatto aggiornato sta attivando il metodo onchange del mio contentObserver? al momento devo compilare l'elenco di tutti i contatti del telefono e inviarli a il mio server remoto, sarebbe molto più semplice inviare semplicemente i dettagli dei contatti che si stanno aggiornando.

Ancora una volta avete indovinato. :). la risposta è no.
Non c'è modo di sapere in modo specifico quale contatto è stato aggiornato. ContentObserver fornisce semplicemente un evento per informarti che sono state apportate alcune modifiche ai dati indicati dall'URI. Ma penso che tu gestisca la situazione in modo inefficiente, poiché stai compilando un elenco di tutti i contatti e li rimandi al server.
Si consiglia di mantenere un elenco di contatti, che vengono inviati correttamente al server, nella memoria locale. E la prossima volta che ricevi una chiamata nel metodo onChange() di contentObserver, vai a prendere tutti i contacts da content_URI, confrontali con l'elenco precedentemente memorizzato e invia solo i contatti aggiornati al server.

3: Questa è la mia domanda principale, quando faccio un cambiamento alla mia lista dei contatti il metodo onChange è essere sparato due volte in rapida successione. 1 cambio, 2 chiamate. Esiste comunque la gestione di ?

Sì, questo succede, ma immagino tu abbia un'impressione sbagliata. Nel mio caso usava sparare a caso due o tre volte o anche più volte. quindi avevo impostato un intervallo di threshold_time. Un intervallo di tempo entro il quale se viene emesso nuovamente ContentObserver, non lo elaborerei. Ho fatto qualcosa di simile ..

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

    } 

Spero che questi suggerimenti/soluzioni aiuterebbero.

+1

+1, il 10000ms secondo funziona in tutti i casi senza errori, avete ricevuto feedback dagli utenti, grazie? –

+0

Non ho ricevuto alcuna risposta da parte degli utenti in merito. Non dirò il suo miglior modo di implementarlo ma funzionerà bene fin da ora.è una specie di patch che abbiamo dovuto implementare. –

+0

Mi piace più 'currentTime = System.CurrentTimeMillis()' 'if (nextCallTime Kobor42

10

Considera come registrare il tuo osservatore. Il secondo argomento di registerContentObserver è boolean notifyForDescendents, è stato impostato su true. quindi verrai avvisato quando ContactsContract.Contacts.CONTENT_URI o qualsiasi dei suoi URL dei discendenti sono stati modificati. Può essere che alcune operazioni per il contatto con un determinato ID attivino la notifica sia per il contatto specifico uri che per i contatti globali uri - con il secondo argomento che è true l'osservatore osserva entrambi.

Un'altra cosa è che è possibile registrare l'osservatore di contenuti per l'ID di contatto specifico uri - ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId). Questo tuttavia non ha nulla a che fare con il tuo problema, ma registrando un osservatore separato per ogni contatto sembra piuttosto brutto;)

Un altro suggerimento: Forse mantenere l'osservatore come campo finale non ricrearlo in onCreate (ma registrarlo solo lì).

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

Per venire al vostro nr. 3: Quanto tempo è tra le due chiamate al tuo osservatore? Penso che il tuo osservatore venga chiamato due volte a causa della sincronizzazione dei contatti, che aggiorna anche il database. Vale a dire. la prima volta è il tuo aggiornamento attuale, la seconda volta è quando la sincronizzazione è finita e registra i suoi valori di sincronizzazione nella stessa riga di contatto.

Potresti disattivare la sincronizzazione e vedere se viene ancora chiamato due volte?

+0

Ah, questa è una buona chiamata. Da allora ho lavorato sulla questione con i consigli sopra forniti, ma la tua risposta è perfettamente logica. –

+0

ha assolutamente senso, non ha provato ma ha un senso .. e se questo è il caso? comunque penso che dobbiamo usare qualche scena di soglia .. – Farhan

-1

Affrontato lo stesso problema nel mio codice e ho scoperto che chiamavo registerContentObserver() due volte. Sebbene fosse per lo stesso identico URI e all'interno della stessa classe, il metodo onChange (boolean selfChange) veniva chiamato due volte come risultato.

0

potresti avere due o più istanze di ContactService che sono tutte registrate nello stesso ContactsContract.Contacts.CONTENT_URI.

Problemi correlati