SyncAdapter работает анимация - как узнать, активно ли SyncAdapter синхронизация

Я хочу показать ProgressBar в ActionBar, в то время как мой SyncAdapter активно синхронизирует контент с Интернетом и из него.

Я попытался использовать SyncStatusObserver вместе с ContentProvider.addStatusChangeListener. Однако я не могу проверить, активно ли активен SyncAdapter. Я могу только проверить:

Эти флаги можно объединить: !isSyncPending && isSyncActive, чтобы можно было проверить, что SyncAdapter активно работает и не имеет ожидающей работы. Однако в некоторых случаях SyncAdapter активно работает и ожидает второго ожидающего запроса.

Кажется, это так просто, но я не могу найти пути решения этой проблемы. Наличие ProgressBar, видимого, когда SyncAdapter не работает, дает пользователям впечатление, что синхронизация выполняется очень медленно. Если он не показывает 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();
    }
}

Ответ 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);
}