2012-10-16 9 views
11

voglio mostrare un ProgressBar nel ActionBar mentre il mio SyncAdapter è attivamente sincronizzazione di contenuti da e verso il web.SyncAdapter animazione in esecuzione - Come sapere se SyncAdapter è attivamente sincronizzando

Ho provato a utilizzare SyncStatusObserver insieme a ContentProvider.addStatusChangeListener. Tuttavia, non posso controllare se un SyncAdapter è attivo. Posso controllare solo:

  1. SyncAdapter è in attesa utilizzando ContentResolver.isSyncPending
  2. SyncAdapter è in attesa o che lavorano attivamente con ContentResolver.isSyncActive

Questi flag possono essere combinate: !isSyncPending && isSyncActive in modo che sia possibile verificare che uno SyncAdapter sta lavorando attivamente e non ha alcun lavoro in sospeso. Tuttavia, in alcuni casi il SyncAdapter funziona attivamente e ha una seconda richiesta in attesa che lo attende.

sembra così semplice, ma non riesco a trovare un modo per aggirare questo problema. Avere il ProgressBar visibile quando SyncAdapter non è in esecuzione dà agli utenti l'impressione che la sincronizzazione sia molto lenta. Non avendo mostrato ProgressBar, l'utente pensa che non stia accadendo nulla.

La soluzione sopra nel codice seguito è mostrata. Registriamo l'osservatore nella activity.onResume:

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

Lo syncObserver viene qui definito come:

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(); 
    } 
} 

risposta

16

infine ho trovato una soluzione al problema. L'idea è quella di utilizzare getCurrentSyncs() o getCurrentSync() metodi del ContentResolver, qualsiasi sia disponibile. I seguenti metodi controlleranno se un'operazione di sincronizzazione sta attualmente lavorando per un account e un'autorità. Richiede il livello 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; 
} 

per attivitá registra poi per gli aggiornamenti in onResume() e annulla la registrazione in onDestroy(). Inoltre, è necessario aggiornare manualmente lo stato in onResume() per raggiungere lo stato corrente.

Ecco un'implementazione che fa proprio questo. Le sottoclassi stessi dovrebbero definire

  • quello account da utilizzare (in attuazione getAccount())
  • cosa authoritity da utilizzare (il campo CONTENT_AUTHORITY)
  • come visualizzare lo stato sychronization (attuazione updateState(boolean isSynchronizing))

spero aiuterà qualcuno in futuro.

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); 
} 
+1

Per Eclair, Froyo, Gingerbread, la soluzione sopra funziona solo se il dispositivo ha un solo account. Se esiste più di un account su un dispositivo, il primo account sarà solo sincronizzato; il resto viene ignorato. – ChuongPham

Problemi correlati