java Content Observer onChange 方法在光标发生 1 次更改后调用两次

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10173996/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 23:55:35  来源:igfitidea点击:

Content Observer onChange method called twice after 1 change in cursor

javaandroidandroid-contentprovider

提问by Kevin Bradshaw

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 remote server of any changes made on the phone to the contacts list.

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

I have set up a ContentObserver on the 'ContactsContract.Contacts.CONTENT_URI' from a service that gets started when the phone is booted.

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

I have a number of quiestions, the first 2 are incidental, the third is my major concern.

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

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?

1:一旦我设置了一个在我的 Cursor 上注册 ContentObserver 的服务,那个观察者是否只存在于服务中?我的意思是,如果服务被杀死,contentObserver 会继续观察吗?

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.

2:我怀疑答案是否定的,但我还是会问。有没有知道正在更新的哪个联系人触发了我的 contentObserver 的 onchange 方法?目前我必须编译电话上所有联系人的列表并将它们发送到我的远程服务器,发送正在更新的联系人的详细信息会容易得多。

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?

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

REsults in 2 quick lines in my logCat:

结果在我的 logCat 中有 2 个快速行:

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

回答by N-JOY

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

我做了一个类似的实现,并设置ContentObserver了日历的事件URI。我遇到了所有的问题,而你现在正面临着。所以你对我的解决方案/建议的问题就在这里......

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?

1) 一旦我设置了一个在我的 Cursor 上注册 ContentObserver 的服务,那个观察者是否只存在于服务中?我的意思是,如果服务被杀死,contentObserver 会继续观察吗?

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.

不,它不会通过 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: 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.

2:我怀疑答案是否定的,但我还是会问。有没有知道正在更新的哪个联系人触发了我的 contentObserver 的 onchange 方法?目前我必须编译电话上所有联系人的列表并将它们发送到我的远程服务器,发送正在更新的联系人的详细信息会容易得多。

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 contentObserveryou fetch all contactsfrom content_URI, compare them with previously stored list and send only updated contacts to server.

你又猜对了。:)。答案是
否定的。没有办法具体知道哪个联系人已更新。ContentObserver 只是提供一个事件,让您知道 uri 指向的数据已经发生了一些变化。但我认为您处理这种情况的效率低下,因为您正在编译所有联系人的列表并将它们发送回服务器。
我建议您在本地存储中维护一个成功发送到服务器的联系人列表。下次当您调用fetch all from 的onChange()方法时,将它们与先前存储的列表进行比较,并仅将更新的联系人发送到服务器。 contentObservercontactscontent_URI

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?

3:这是我的主要问题,当我对我的联系人列表进行更改时,onChange 方法会连续快速触发两次。1 次更改,2 次调用。有没有办法管理这个?

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 ContentObserveris fired again, then i would not process it. I did something like this..

是的,这会发生,但我想你的印象是错误的。就我而言,它曾经随机发射两次或三次甚至更多次。所以我设置了一个 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();
        }

    }  

Hope these suggestions/solutions would help.

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

回答by Tomasz Gawel

Consider how you register your observer. The second argument of registerContentObserveris 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 trueyour observer observes both.

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

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

另一件事是,您可以为特定的联系人 ID uri - 注册内容观察者ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId)。然而,这与您的问题无关,但为每个联系人注册单独的观察者看起来很丑陋;)

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

另一个建议:也许将观察者保留为最终字段,不要在 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();
    }
}

回答by dizzl

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.

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

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

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

回答by u6702707

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

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

回答by fusiller

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.

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