2012-04-16 27 views
14

我有一個應用程序,我希望將android聯繫人列表中的詳細信息發送到遠程服務器,以便用戶可以在線查看他的聯繫人。 爲此,我想通知遠程服務器在手機上對聯繫人列表進行的任何更改。內容觀察者onChange方法在光標更改後調用兩次

我已經在電話啓動時啓動的服務中的'ContactsContract.Contacts.CONTENT_URI'上設置了ContentObserver。

我有一些quiestions,第2個是偶然的,第三個是我主要關心的。

1:一旦我建立了一個在我的光標上註冊ContentObserver的服務,那麼這個觀察者是否只存在於服務中?我的意思是,如果服務被殺死,contentObserver是否繼續觀察?

2:我懷疑答案是否定的,但我仍然會問。是否有任何知道哪些聯繫人正在更新觸發我的contentObserver的onchange方法?目前我必須編譯手機上所有聯繫人的列表,並將它們發送到我的遠程服務器,只需發送正在更新的聯繫人的詳細信息就會更容易。

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

結果在2條快線在我的logcat:

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

回答

29

我做了一個類似的實現,並已成立一個ContentObserver在日曆中的活動URI。我面臨所有問題,你現在正面臨着這些問題。所以,我的解決方案/建議,你的問題已在這裏....

1)當我已經設置了對 我的光標註冊一個ContentObserver服務, 這是否僅觀察員服務中存在嗎?我的意思是,如果該服務被殺害,contentObserver會繼續觀察嗎? ?

不,它不會觀察您的內容通過URI的內容。但有解決方案。您可以創建一個始終運行的服務。一旦由於內存問題或其他意外解僱而被解僱時,該服務將再次創建。除非明確否認,否則它將繼續運行。要在您的服務等級中創建此類服務覆蓋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指向的數據進行了一些更改。但我認爲你正在低效地處理這種情況,因爲你正在編譯所有聯繫人列表並將它們發送回服務器。
我建議你在本地存儲器中維護一個成功發送到服務器的聯繫人列表。並且下一次當您撥打onChange()方法contentObserver時,您將從content_URI中獲取所有contacts,將它們與以前存儲的列表進行比較,並僅將更新的聯繫人發送到服務器。

3:這是我的主要問題,當我做出改變,以我的聯繫人列表 的方法的onChange是 快速連續被解僱兩次。 1次更換,2次電話。無論如何管理 這?

是的這種情況發生了,但我想你的印象是錯誤的。在我的情況下,它會隨機發生兩次或三次甚至更多次。所以我設置了一個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(); 
     } 

    } 

希望這些建議/解決方案將有所幫助。

+1

+1,是否10000毫秒在所有情況下都可以正常工作,您是否從用戶那裏得到過任何反饋,謝謝? – 2012-09-03 17:45:20

+0

我還沒有得到任何用戶對此的迴應。我不會說它的最佳實施方式,但它現在的工作狀況良好。它是我們必須實現的一種補丁。 – 2012-09-04 08:59:20

+0

我更喜歡'currentTime = System.CurrentTimeMillis()''if(nextCallTime Kobor42 2013-10-09 06:06:11

10

考慮如何註冊您的觀察員。 registerContentObserver的第二個參數是boolean notifyForDescendents,您已將其設置爲true。所以當ContactsContract.Contacts.CONTENT_URI或其任何descandants uris被更改時,您會收到通知。這可能是某些與給定ID聯繫的操作會觸發通知,既針對特定聯繫人uri和全局聯繫人uri - 第二個參數是您觀察者觀察到的true

另一件事是,您可以註冊特定聯繫人id的內容觀察員 - 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(); 
    } 
} 
5

來到您的nr。 3:向觀察者發出兩次電話之間有多少時間?我認爲你的觀察者會因聯繫人同步而被調用兩次,這也會更新數據庫。 IE瀏覽器。第一次是您的實際更新,第二次是同步完成並將其同步值註冊到同一聯繫人行中。

你可以關閉同步,看看它是否仍然被調用兩次?

+0

啊,這是一個很好的電話。 Ive自從用上面提供的建議解決了這個問題,但你的回答很有道理。 – 2012-09-17 10:36:11

+0

完全合理,沒有嘗試但有道理..如果是這樣的話呢?我仍然認爲我們需要使用一些閾值場景.. – Farhan 2014-04-15 07:48:43

-1

在我自己的代碼中面臨同樣的問題,並發現我調用了兩次registerContentObserver()。雖然它是爲完全相同的URI,並在同一類中,我的onChange(boolean selfChange)方法被調用兩次作爲結果。

0

您可能有兩個或兩個以上的ContactService實例,它們都被註冊爲相同的ContactsContract.Contacts.CONTENT_URI。

相關問題