11

SyncAdapter がコンテンツを Web との間でアクティブに同期している間、ActionBar に ProgressBar を表示したいと考えています。

SyncStatusObserverをContentProvider.addStatusChangeListenerと一緒に使用してみました。ただし、SyncAdapter がアクティブに実行されているかどうかを確認できません。私は確認することができます:

  1. SyncAdapter は ContentResolver.isSyncPending を使用して保留中です
  2. SyncAdapter は保留中であるか、ContentResolver.isSyncActiveを使用してアクティブに動作しています

これらのフラグは組み合わせることができます。!isSyncPending && isSyncActiveこれにより、SyncAdapter がアクティブに動作しており、保留中の作業がないことを確認できます。ただし、場合によっては、SyncAdapter がアクティブに動作していて、2 番目の保留中の要求がそれを待っていることがあります。

とても簡単に思えますが、この問題を回避する方法が見つかりません。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();
    }
}
4

1 に答える 1

17

私はついに問題の解決策を見つけました。アイデアは、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);
}
于 2012-11-01T14:38:32.160 に答える