2012-10-16 70 views
11

我想在ActionBar中顯示ProgressBar,同時我的SyncAdapter主動將內容同步到網絡和從網絡同步內容。SyncAdapter運行動畫 - 如何知道SyncAdapter是否正在同步

我試過用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(); 
    } 
} 

回答

16

我終於找到了解決問題的辦法。這個想法是使用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; 
} 

一個活動然後註冊爲onDestroy()onResume()更新和註銷。此外,必須手動更新狀態onResume()以趕上當前狀態。

這是一個實現這一點的實現。子類應自行確定

  • 要使用哪個帳戶(實施getAccount()
  • 使用什麼authoritity(場CONTENT_AUTHORITY
  • 如何顯示sychronization狀態(實現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); 
} 
+1

對於Eclair,Froyo,Gingerbread,上述解決方案僅適用於設備只有一個帳戶的情況。如果設備上存在多個帳戶,則第一個帳戶將僅同步;其餘的被忽略。 – ChuongPham