tob*_*obs 12 android synchronization android-contentresolver android-syncadapter swiperefreshlayout
我目前正在开发一个Android应用程序,它依赖于SyncAdapter从服务器刷新其内容.我基本上遵循了这些说明:https://developer.android.com/training/sync-adapters/creating-sync-adapter.html
直到最近,这仍然很好.我知道这可能听起来很愚蠢,但老实说我不知道我是怎么搞砸的:(
我有一个ContentProvider,因此SyncAdapter我想要同步的所有项目的一个和一个帐户.我使用整数标志来确定哪个项目必须同步:
public static final int EVENTS = 0x1;
public static final int NEWS = 0x2;
public static final int SUBSTITUTIONS = 0x4;
public static final int TEACHERS = 0x8;
public static final int ALL = 0xF;
Run Code Online (Sandbox Code Playgroud)
所以在我看来onPerformSync我有类似的东西:
ArrayList<ContentProviderOperation> batchList = new ArrayList<>();
int which = extras.getInt(SYNC.ARG, SYNC.ALL);
if((which & SYNC.NEWS) == SYNC.NEWS) { syncNews(provider, batchList, syncResult, 0, 1); }
if((which & SYNC.EVENTS) == SYNC.EVENTS) { syncEvents(provider, batchList, syncResult); }
if((which & SYNC.TEACHERS) == SYNC.TEACHERS) { syncTeachers(provider, batchList, syncResult); }
if((which & SYNC.SUBSTITUTIONS) == SYNC.SUBSTITUTIONS) { syncSubstitutions(provider, batchList, syncResult); }
Log.i(TAG, "Merge solution ready. Applying batch update to database...");
provider.applyBatch(batchList);
Run Code Online (Sandbox Code Playgroud)
因为我也希望用户能够强制刷新,我使用a SwipeRefreshLayout启动同步服务:
@Override
public void onRefresh() {
Log.d(TAG, "Force refresh triggered!");
SyncUtils.triggerRefresh(SyncAdapter.SYNC.NEWS | SyncAdapter.SYNC.EVENTS);
}
Run Code Online (Sandbox Code Playgroud)
我还想监视同步状态,所以我SyncStatusObserver在我的片段中注册/取消注册一个onResume/ onPause:
private final SyncStatusObserver syncStatusObserver = new SyncStatusObserver() {
@Override
public void onStatusChanged(int which) {
Account account = AuthenticatorService.getAccount(SyncUtils.ACCOUNT_TYPE);
boolean syncActive = ContentResolver.isSyncActive(account, DataProvider.AUTHORITY);
boolean syncPending = ContentResolver.isSyncPending(account, DataProvider.AUTHORITY);
final boolean refresh = syncActive || syncPending;
Log.d(TAG, "Status change detected. Active: %b, pending: %b, refreshing: %b", syncActive, syncPending, refresh);
swipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
swipeRefreshLayout.setRefreshing(refresh);
}
});
}
};
Run Code Online (Sandbox Code Playgroud)
每当我启动应用程序时,Refresh layout都会指示同步处于活动状态.我记录了几乎所有内容,发现同步处于挂起状态.每当我尝试强制刷新时,同步也会
这是一个示例日志:
D/HomeFragment? Status change detected. Active: false, pending: true, refreshing: true
D/HomeFragment? Status change detected. Active: false, pending: true, refreshing: true
D/HomeFragment? Status change detected. Active: true, pending: true, refreshing: true
D/HomeFragment? Status change detected. Active: false, pending: true, refreshing: true
Run Code Online (Sandbox Code Playgroud)
如您所见,永远不会Active: false, pending: false指示同步已完成.这真的磨砺我的齿轮.
我在我的应用程序类中进行存根帐户(和定期同步)的初始设置:
public static void createSyncAccount(Context context) {
boolean newAccount = false;
boolean setupComplete = PreferenceManager
.getDefaultSharedPreferences(context).getBoolean(PREF_SETUP_COMPLETE, false);
// Create account, if it's missing. (Either first run, or user has deleted account.)
Account account = AuthenticatorService.getAccount(ACCOUNT_TYPE);
AccountManager accountManager =
(AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
if (accountManager.addAccountExplicitly(account, null, null)) {
// Inform the system that this account supports sync
ContentResolver.setIsSyncable(account, DataProvider.AUTHORITY, 1);
// Inform the system that this account is eligible for auto sync when the network is up
ContentResolver.setSyncAutomatically(account, DataProvider.AUTHORITY, true);
// Recommend a schedule for automatic synchronization. The system may modify this based
// on other scheduled syncs and network utilization.
requestPeriodic(account, SYNC.EVENTS, 172800);
requestPeriodic(account, SYNC.NEWS, 604800);
requestPeriodic(account, SYNC.SUBSTITUTIONS, 1800);
requestPeriodic(account, SYNC.TEACHERS, 2419200);
newAccount = true;
}
// Schedule an initial sync if we detect problems with either our account or our local
// data has been deleted. (Note that it's possible to clear app data WITHOUT affecting
// the account list, so wee need to check both.)
if (newAccount || !setupComplete) {
triggerRefresh(SYNC.ALL);
PreferenceManager.getDefaultSharedPreferences(context).edit()
.putBoolean(PREF_SETUP_COMPLETE, true).commit();
}
}
Run Code Online (Sandbox Code Playgroud)
凡requestPeriodic()如下:
public static void requestPeriodic(Account account, int which, long seconds) {
Bundle options = new Bundle();
options.putInt(SYNC.ARG, which);
ContentResolver.addPeriodicSync(account,
DataProvider.AUTHORITY, options, seconds);
}
Run Code Online (Sandbox Code Playgroud)
我triggerRefresh()看起来像:
public static void triggerRefresh(int which) {
Log.d(TAG, "Force refresh triggered for id: %d", which);
Bundle options = new Bundle();
options.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
options.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
options.putInt(SYNC.ARG, which);
ContentResolver.requestSync(
AuthenticatorService.getAccount(ACCOUNT_TYPE),
DataProvider.AUTHORITY,
options
);
}
Run Code Online (Sandbox Code Playgroud)
有没有人遇到类似的问题或者我错了什么?
我试着改变我使用的方式SyncStatusObserver.我现在从whichflag参数中获取信息,如下所示:
private final SyncStatusObserver syncStatusObserver = new SyncStatusObserver() {
@Override
public void onStatusChanged(int which) {
boolean syncActive = (which & ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE) == ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
boolean syncPending = (which & ContentResolver.SYNC_OBSERVER_TYPE_PENDING) == ContentResolver.SYNC_OBSERVER_TYPE_PENDING;
boolean refreshing = syncActive || syncPending;
// update UI...
}
};
Run Code Online (Sandbox Code Playgroud)
当我这样做时,pending状态似乎是正确的,所以它false在适配器启动同步过程后立即返回,但现在适配器始终保持活动状态并且我boolean refreshing一如既往地得到相同的错误结果.:/
我的syncAdapter遇到了类似的问题...我解决的问题是关闭自动同步...因为你明确触发同步过程你可以删除现有帐户将内容解析器的setSyncAutomatically设置为false并运行适配器再次......
ContentResolver.setSyncAutomatically(account, CONTENT_AUTHORITY, false);
Run Code Online (Sandbox Code Playgroud)
我还发布了SyncAdapter的状态更改回调,其中记录了同步过程的状态
private SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() {
@Override
public void onStatusChanged(int which) {
Log.e("TAG", "Sync Status " + which);
runOnUiThread(new Runnable() {
@Override
public void run() {
Account account = GenericAccountService.getAccount(SyncUtils.ACCOUNT_TYPE);
if (account == null) {
// GetAccount() returned an invalid value. This shouldn't happen, but
// we'll set the status to "not refreshing".
//setRefreshActionButtonState(false);
return;
}
// Test the ContentResolver to see if the sync adapter is active or pending.
// Set the state of the refresh button accordingly.
boolean syncActive = ContentResolver.isSyncActive(
account, PlacesProvider.PROVIDER_NAME);
boolean syncPending = ContentResolver.isSyncPending(
account, PlacesProvider.PROVIDER_NAME);
Log.e("TAG", "SYNC PENDING " + syncPending);
if (!syncActive && !syncPending){
Log.e("TAG", "Sync is finished");
//if (syncProgressDialog != null) syncProgressDialog.dismiss();
// progressDialog.hide();
}
else {
}
//setRefreshActionButtonState(syncActive || syncPending);
}
});
}
};
Run Code Online (Sandbox Code Playgroud)
在onResume中,我注册了SyncStatusObserver
mSyncStatusObserver.onStatusChanged(0);
final int mask = ContentResolver.SYNC_OBSERVER_TYPE_PENDING |
ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
mSyncObserverHandle = ContentResolver.addStatusChangeListener(mask, mSyncStatusObserver);
Run Code Online (Sandbox Code Playgroud)
并在onStop中我删除了监听器
if (mSyncObserverHandle != null) {
ContentResolver.removeStatusChangeListener(mSyncObserverHandle);
mSyncObserverHandle = null;
mSyncStatusObserver = null;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1122 次 |
| 最近记录: |