如何知道同步何时完成?

31

我已经实现了一个同步适配器,并希望在我的活动中在其完成时得到回调。我尝试使用ContentResolver.addStatusChangeListener,但只有在同步处于待处理/活动状态时才会收到回调。这是来自我的活动的一些相关代码:

@Override
protected void onResume() {
    super.onResume();
    final int mask = ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE | ContentResolver.SYNC_OBSERVER_TYPE_PENDING;
    syncObserverHandle = ContentResolver.addStatusChangeListener(mask, syncStatusObserver);
}

@Override
protected void onPause() {
    super.onPause();
    if (syncObserverHandle != null) {
        ContentResolver.removeStatusChangeListener(syncObserverHandle);
        syncObserverHandle = null;
    }
}

private SyncStatusObserver syncStatusObserver = new SyncStatusObserver() {

    @Override
    public void onStatusChanged(int which) {
        AccountManager am = AccountManager.get(TodosActivity.this);
        Account a = am.getAccountsByType(Const.ACCOUNT_TYPE)[0];

        Log.d(Const.TAG, "Sync status changed: " + which);

        if (!ContentResolver.isSyncActive(a, DataProvider.AUTHORITY) &&
                !ContentResolver.isSyncPending(a, DataProvider.AUTHORITY)) {
            Log.d(Const.TAG, "Sync finished, should refresh nao!!");
        }
    }
};

然而,在onStatusChanged方法中的if语句从未生效。我是从JumpNote演示中获取此示例的,它可以正常工作,可能是因为它也在onResume()中手动调用,所以当同步完成时系统不会自动调用它。或者,我做错了什么?以下是我在logcat中得到的内容:
D/MYAPP (10903): Sync status changed: 2
D/MYAPP (10903): Sync status changed: 2
D/MYAPP (10903): Sync status changed: 4
D/MYAPP (10981): --> DataSyncAdapter.onPerformSync()
D/MYAPP (10981): <-- DataSyncAdapter.onPerformSync()
D/MYAPP (10903): Sync status changed: 4

所以,看起来我可以依靠第二个SYNC_OBSERVER_TYPE_ACTIVE(4)状态更改来刷新我的数据,但那看起来非常丑陋。有任何想法吗?

3个回答

42

我发现的一种解决方案是完全放弃使用ContentResolver,并实现自己的广播。基本上,在同步适配器中添加以下内容,放在onPerformSync的结尾处:

Intent i = new Intent(SYNC_FINISHED);
sendBroadcast(i);

在活动中的代码:

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(syncFinishedReceiver, new IntentFilter(DataSyncService.SYNC_FINISHED));
}

@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(syncFinishedReceiver);
}

private BroadcastReceiver syncFinishedReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(Const.TAG, "Sync finished, should refresh nao!!");
    }
};

这似乎很好用,但我希望在SDK中找到直接通知我同步完成的内容。


1
+1 我使用 ContentResolver.isSyncActive 浪费了一小时时间。自己实现其实更容易。 - rds
当你说:“在同步服务中添加这个”时,你实际上是指同步适配器吗?“...在最后”让我想到:一旦同步完成,在onPerformSync的结尾。 - HGPB
2
我不明白这个,sendBroadcast和SYNC_FINISHED是什么? - Pedro Paulo Amorim
2
请查看以下答案以获得更好的描述:http://stackoverflow.com/questions/9433674/get-notified-when-requestsync-function-completed - easycheese

17

奇怪的是,对我来说它是可以工作的。

在我的Activity中,我有:

  @Override
  protected void onPause() {
    super.onPause();
    ContentResolver.removeStatusChangeListener(mContentProviderHandle);
  }

  @Override
  protected void onResume() {
    super.onResume();
    mContentProviderHandle = ContentResolver.addStatusChangeListener(
        ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE, this);
  }

  @Override
  public void onStatusChanged(int which) {
    AccountManager accountManager = AccountManager.get(this);
    Account[] accounts = accountManager
        .getAccountsByType(AuthenticatorActivity.PARAM_ACCOUNT_TYPE);

    if (accounts.length <= 0) {
      return;
    }

    updateRefresh(ContentResolver.isSyncActive(accounts[0],
        MyContentProvider.AUTHORITY));
  }

  // Since onStatusChanged() is not called from the main thread
  // I need to update the ui in the ui-thread.
  private void updateRefresh(final boolean isSyncing) {
    runOnUiThread(new Runnable() {

      @Override
      public void run() {
        if (isSyncing) {
          mRefreshMenu.setActionView(R.layout.menu_item_refresh);
        } else {
          mRefreshMenu.setActionView(null);
        }
      }
    });
  }

2
这对我有用,尽管我不得不添加两个权限:GET_ACCOUNTS,READ_SYNC_STATS。 - android developer
"@Override public void onStatusChanged" >> "该方法不重写其超类的方法。" - Eftekhari
顺便说一句,我认为在活动暂停和恢复时添加和删除监听器是没有意义的。实际上,它只会使逻辑变得更加复杂,并留下一个漏洞:如果同步状态在暂停时发生更改,则 UI 将永远不会指示它。为了使此代码正确,您需要在每次 onResume 时检查同步状态,以防它在暂停时更新。但这是不必要的。在暂停时更新 UI 是安全的,您只需不运行动画或执行持续消耗 CPU 的操作即可。 - Avi Cherry

6

我曾经做过类似的工作,然后我在onStatusChanged函数末尾添加了一个Log.d,但它没有执行!

于是,在调试和试错了15分钟后,我意识到我需要添加READ_SYNC_STATS权限,虽然我已经有GET_ACCOUNTS权限了。所以,请检查您是否获得了正确的权限,问题不在于"if"语句是否成立,而在于它总是退出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接