内容观察者onChange方法在光标1更改后调用两次

Kev*_*haw 17 java android android-contentprovider

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

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

我有一些静止,前两个是偶然的,第三个是我的主要关注点.

1:一旦我设置了一个在我的Cursor上注册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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

 detected change in contacts: false 
 detected change in contacts: false
Run Code Online (Sandbox Code Playgroud)

N-J*_*JOY 31

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

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

不,它不会通过URI观察您的内容的内容.但是有解决方案.您可以创建一个始终运行的服务.由于某些内存问题或其他意外解雇,该服务将在解除后立即再次创建.除非明确驳回,否则它将一直继续运行.OnStartCommand(Intent intent, int flags, final int startId)在Service类中创建此类服务覆盖并返回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;
}  
Run Code Online (Sandbox Code Playgroud)

.

2:我怀疑答案是否定的,但无论如何我都会问.无论如何知道哪个联系人正在更新触发我的contentObserver的onchange方法?目前我必须编制手机上所有联系人的列表并将其发送到我的远程服务器,发送更新的联系人的详细信息会更容易.

你再次猜对了.:) 答案是
否定的.无法确切知道哪个联系人已更新.ContentObserver只提供一个事件,让您知道对uri指向的数据进行了一些更改.但我认为你正在低效地处理这种情况,因为你正在编译所有联系人的列表并将它们发送回服务器.
我建议你在本地存储中维护一个成功发送到服务器的联系人列表.而当你在通话下次onChange()方法contentObserver你获取所有contactscontent_URI,他们与先前存储的列表进行比较,并只发送更新的联系人到服务器.

3:这是我的主要问题,当我对我的联系人列表进行更改时,onChange方法会连续两次触发.1次更改,2次通话.无论如何管理这个?

是的,这发生了,但我猜你的印象不对.在我的情况下,它曾经随机射击两次或三次甚至更多次.所以我设置了threshold_time间隔.if 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();
        }

    }  
Run Code Online (Sandbox Code Playgroud)

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


Tom*_*wel 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();
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

来吧你的nr.3:两次给观察者的电话之间有多长时间?我认为你的观察者因为联系人同步而被调用两次,这也会更新数据库.IE浏览器.第一次是您的实际更新,第二次是同步完成并在同一联系行中注册其同步值.

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