【问题标题】:SyncAdapter running animation - how to know if SyncAdapter is actively synchronizingSyncAdapter 运行动画——如何知道 SyncAdapter 是否在主动同步
【发布时间】:2014-03-04 01:59:47
【问题描述】:

我想在我的 SyncAdapter 主动与网络同步内容时,在 ActionBar 中显示一个 ProgressBar。

我尝试将SyncStatusObserverContentProvider.addStatusChangeListener 一起使用。但是,我无法检查 SyncAdapter 是否正在运行。我只能检查:

  1. SyncAdapter 正在等待使用 ContentResolver.isSyncPending
  2. SyncAdapter 正在等待或正在使用ContentResolver.isSyncActive 积极工作

这些标志可以组合使用:!isSyncPending && isSyncActive,以便可以检查 SyncAdapter 是否正在工作并且没有任何待处理的工作。但是,在某些情况下,SyncAdapter 正在积极工作并且有第二个待处理的请求在等待它。

看起来很简单,但我找不到解决这个问题的方法。在 SyncAdapter 未运行时显示 ProgressBar 会给用户一种同步非常慢的印象。让它不显示 ProgressBar 会让用户认为没有发生任何事情。

上面的代码解决方案如下所示。我们在activity.onResume中注册观察者:

 int mask = ContentResolver.SYNC_OBSERVER_TYPE_PENDING | ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
 syncHandle = ContentResolver.addStatusChangeListener(mask, syncObserver);

syncObserver 在这里定义为:

syncObserver = new SyncStatusObserver()
{
    @Override
    public void onStatusChanged(int which)
    {
        Account account = getSomeAccount();
        boolean syncActive = ContentResolver.isSyncActive(account, CONTENT_AUTHORITY);
        boolean syncPending = ContentResolver.isSyncPending(account, CONTENT_AUTHORITY);
        boolean isSynchronizing = syncActive && !syncPending;
        updateRefreshButtonState();
    }
}

【问题讨论】:

    标签: android android-contentresolver android-syncadapter


    【解决方案1】:

    我终于找到了解决问题的方法。这个想法是使用 ContentResolver 的 getCurrentSyncs()getCurrentSync() 方法,无论哪个可用。以下方法将检查同步操作当前是否适用于帐户和权限。它需要 API 级别 8 (Froyo = Android 2.2)。

    private static boolean isSyncActive(Account account, String authority)
    {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        {
            return isSyncActiveHoneycomb(account, authority);
        } else
        {
            SyncInfo currentSync = ContentResolver.getCurrentSync();
            return currentSync != null && currentSync.account.equals(account) &&
                   currentSync.authority.equals(authority);
        }
    }
    
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private static boolean isSyncActiveHoneycomb(Account account, String authority)
    {
        for(SyncInfo syncInfo : ContentResolver.getCurrentSyncs())
        {
            if(syncInfo.account.equals(account) &&
               syncInfo.authority.equals(authority))
            {
                return true;
            }
        }
        return false;
    }
    

    然后一个活动在onResume() 中注册更新并在onDestroy() 中取消注册。此外,必须手动更新 onResume() 中的状态以赶上当前状态。

    这是一个可以做到这一点的实现。子类应该自己定义

    • 使用什么帐户(实现getAccount()
    • 使用什么权限(CONTENT_AUTHORITY 字段)
    • 如何显示同步状态(实现updateState(boolean isSynchronizing)

    希望以后能对大家有所帮助。

    import android.accounts.Account;
    import android.annotation.TargetApi;
    import android.app.Activity;
    import android.content.ContentResolver;
    import android.content.SyncInfo;
    import android.content.SyncStatusObserver;
    import android.os.Build;
    import android.os.Bundle;
    
    public abstract class SyncActivity extends Activity
    {
        private static final String CONTENT_AUTHORITY = "com.example.authority";
        private Object syncHandle;
        private SyncStatusObserver observer;
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
    
            observer = new SyncStatusObserver()
            {
                @Override
                public void onStatusChanged(int which)
                {
                    runOnUiThread(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            Account account = getAccount();
                            boolean isSynchronizing =
                                    isSyncActive(account, CONTENT_AUTHORITY);
                            updateState(isSynchronizing);
                        }
                    });
                }
            };
        }
    
        @Override
        protected void onResume()
        {
            super.onResume();
    
            // Refresh synchronization status
            observer.onStatusChanged(0);
    
            // Watch for synchronization status changes
            final int mask = ContentResolver.SYNC_OBSERVER_TYPE_PENDING |
                    ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
            syncHandle = ContentResolver.addStatusChangeListener(mask, observer);
        }
    
        @Override
        protected void onPause()
        {
            super.onPause();
    
            // Remove our synchronization listener if registered
            if (syncHandle != null)
            {
                ContentResolver.removeStatusChangeListener(syncHandle);
                syncHandle = null;
            }
        }
    
        private static boolean isSyncActive(Account account, String authority)
        {
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
            {
                return isSyncActiveHoneycomb(account, authority);
            } else
            {
                SyncInfo currentSync = ContentResolver.getCurrentSync();
                return currentSync != null && currentSync.account.equals(account) 
                        && currentSync.authority.equals(authority);
            }
        }
    
        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        private static boolean isSyncActiveHoneycomb(Account account,
                                                             String authority)
        {
            for(SyncInfo syncInfo : ContentResolver.getCurrentSyncs())
            {
                if(syncInfo.account.equals(account) &&
                        syncInfo.authority.equals(authority))
                {
                    return true;
                }
            }
            return false;
        }
    
        protected abstract Account getAccount();
        protected abstract void updateState(boolean isSynchronizing);
    }
    

    【讨论】:

    • 对于 Eclair、Froyo、Gingerbread,上述解决方案仅适用于设备只有一个帐户的情况。如果设备上存在多个帐户,则只会同步第一个帐户;其余的被忽略。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多