【问题标题】:How to know when sync is finished?如何知道同步何时完成?
【发布时间】:2011-07-08 09:13:00
【问题描述】:

我已经实现了一个同步适配器,我想在它完成我的活动时得到一个回调。我曾尝试使用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 demo 中提取了这个例子,它可能是因为它也在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) 状态更改来刷新我的数据,但这看起来真的很难看。有什么想法吗?

【问题讨论】:

    标签: android callback sync


    【解决方案1】:

    我找到的一个解决方案是完全放弃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 我在ContentResolver.isSyncActive 上浪费了一个小时。自己做实际上要容易得多。
    • 当你说:"add this in the sync service" 你真的是指同步适配器吗? "...at the end" 让我想到:一旦同步在 onPerformSync 结束时完成。
    • 这个我看不懂,sendBroadcast 和 SYNC_FINISHED 是什么?
    • 查看这个答案以获得更好的描述:stackoverflow.com/questions/9433674/…
    【解决方案2】:

    奇怪,它确实对我有用。

    在我的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
    • @Override public void onStatusChanged >> “方法不会覆盖其超类中的方法”。 ??
    • 顺便说一句,我认为在活动暂停和恢复时添加和删除侦听器没有任何意义。事实上,它只会使逻辑复杂化,并且给这个示例留下一个错误:如果同步状态在暂停时发生变化,UI 将永远不会指示它。要使此代码正确,您需要检查每个 onResume 的同步状态,以防它在暂停时更新。但这是不必要的。在暂停时更新 UI 是安全的,您只是不应该运行动画或执行持续消耗 CPU 的操作。
    【解决方案3】:

    我正在处理类似的事情,并且在 onStatusChanged 函数的末尾还有一个 Log.d,但它没有执行!

    所以在调试和试错 15 分钟后,我意识到我需要添加 READ_SYNC_STATS 权限,但我已经拥有 GET_ACCOUNTS 权限。所以,请检查您是否获得了正确的许可,不是“如果”不成立,而是它一直在保释。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-22
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多