17

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

我在“ContactsContract.Contacts.CONTENT_URI”上设置了一个 ContentObserver,该服务在手机启动时启动。

我有很多问题,前两个是偶然的,第三个是我主要关心的问题。

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

在我的 logCat 中有 2 行快速生成:

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

5 回答 5

31

我做了一个类似的实现,并设置了一个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 指向的数据发生了一些变化。但是我认为您处理这种情况的效率很低,因为您正在编译所有联系人的列表并将它们发送回服务器。
我建议您在本地存储中维护一个成功发送到服务器的联系人列表。下次当您在fetch all fromonChange()方法中接到电话时,将它们与先前存储的列表进行比较,并仅将更新的联系人发送到服务器。 contentObservercontactscontent_URI

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

    }  

希望这些建议/解决方案会有所帮助。

于 2012-05-25T10:25:42.150 回答
12

考虑如何注册观察者。的第二个参数registerContentObserverboolean notifyForDescendents,您已将其设置为true。因此,当 ContactsContract.Contacts.CONTENT_URI 或其任何 descandants uris 发生更改时,您将收到通知。与给定 id 联系的某些操作可能会触发特定联系人 uri 和全局联系人 uri 的通知 - 第二个参数是true您的观察者同时观察两者。

另一件事是您可以为特定的联系人 id 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();
    }
}
于 2012-05-26T15:23:50.760 回答
5

来找你的nr。3:两次调用观察者之间的时间间隔是多少?我认为您的观察者会因为联系人同步而被调用两次,这也会更新数据库。IE。第一次是您的实际更新,第二次是同步完成并将其同步值注册在同一联系人行中。

你能关闭同步,看看它是否仍然被调用两次?

于 2012-09-16T13:32:56.337 回答
0

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

于 2016-08-11T01:07:38.190 回答
-1

在我自己的代码中遇到了同样的问题,发现我调用了 registerContentObserver() 两次。虽然它是针对完全相同的 URI 并且在同一个类中,但结果我的 onChange(boolean selfChange) 方法被调用了两次。

于 2014-11-12T14:02:52.237 回答