Android 用户登录后重新运行/继续SyncAdapter
如果在Android 用户登录后重新运行/继续SyncAdapter,android,accountmanager,android-syncadapter,Android,Accountmanager,Android Syncadapter,如果在SyncAdapter.onPerformSync中,固有的身份验证令牌获取导致用户需要输入密码,用户成功登录后,如何重新运行或继续同步 虽然这似乎是一个相当标准的功能,但我一直找不到它的任何内容。似乎暗示要使用,但我尝试过,它从未被调用。此外,如果我对文档理解正确的话,任何账户的任何变更都会被要求,这似乎有点……间接 编辑 下面是我代码的相关部分。我一直密切关注这一点,这一点非常好 在Authenticator.getAuthToken中 // There is neither an a
SyncAdapter.onPerformSync
中,固有的身份验证令牌获取导致用户需要输入密码,用户成功登录后,如何重新运行或继续同步
虽然这似乎是一个相当标准的功能,但我一直找不到它的任何内容。似乎暗示要使用,但我尝试过,它从未被调用。此外,如果我对文档理解正确的话,任何账户的任何变更都会被要求,这似乎有点……间接
编辑
下面是我代码的相关部分。我一直密切关注这一点,这一点非常好
在Authenticator.getAuthToken中
// There is neither an access nor a refresh token. User has to log in
if (!tokens.hasAccess() && !tokens.hasRefresh()) {
Intent intent = new Intent(context, LoginActivity.class);
intent.putExtra(LoginActivity.ARG_ACCOUNT, account);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); // As per AbstractAccountAuthenticator doc
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
}
...
return bundle;
// Store access token if one was provided. Note that this should always be the case anyway,
// otherwise the login would have been unsuccessful
if (tokens.hasAccess()) {
manager.setAuthToken(account, Authenticator.TOKEN_TYPE_ACCESS, tokens.access);
}
// Store refresh token if one was provided.
if (tokens.hasRefresh()) {
manager.setAuthToken(account, Authenticator.TOKEN_TYPE_REFRESH, tokens.refresh);
}
final Intent intent = new Intent();
if (tokens.hasAccess()) {
intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
intent.putExtra(AccountManager.KEY_AUTHTOKEN, tokens.access);
}
setAccountAuthenticatorResult(intent.getExtras());
setResult(Activity.RESULT_OK, intent);
finish();
在LoginActivity.finishLogin中
// There is neither an access nor a refresh token. User has to log in
if (!tokens.hasAccess() && !tokens.hasRefresh()) {
Intent intent = new Intent(context, LoginActivity.class);
intent.putExtra(LoginActivity.ARG_ACCOUNT, account);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); // As per AbstractAccountAuthenticator doc
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
}
...
return bundle;
// Store access token if one was provided. Note that this should always be the case anyway,
// otherwise the login would have been unsuccessful
if (tokens.hasAccess()) {
manager.setAuthToken(account, Authenticator.TOKEN_TYPE_ACCESS, tokens.access);
}
// Store refresh token if one was provided.
if (tokens.hasRefresh()) {
manager.setAuthToken(account, Authenticator.TOKEN_TYPE_REFRESH, tokens.refresh);
}
final Intent intent = new Intent();
if (tokens.hasAccess()) {
intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
intent.putExtra(AccountManager.KEY_AUTHTOKEN, tokens.access);
}
setAccountAuthenticatorResult(intent.getExtras());
setResult(Activity.RESULT_OK, intent);
finish();
而且,尽管这有点微不足道:
在SyncAdapter.onPerformSync中:
String token = null;
try {
token = AccountManager.get(getContext()).blockingGetAuthToken(account, Authenticator.TOKEN_TYPE_ACCESS, true);
if (token == null) {
syncResult.stats.numAuthExceptions++;
return;
}
} catch (OperationCanceledException x) {
return;
} catch (AuthenticatorException x) {
syncResult.stats.numAuthExceptions++;
return;
} catch (IOException x) {
syncResult.stats.numIoExceptions++;
return;
}
经过一番讨论,我相信您需要的是:
ContentResolver.requestSync(account, Contract.AUTHORITY, new Bundle());
当需要用户交互来完成同步时,您的帐户经理会很合理地导致blockingGetAuthToken立即返回null。您只需要安排,当用户完成操作(验证自己)时,您请求新的同步。上面的代码就可以了。您不必重新运行它。如果您使用AccountManager.blockingGetAuthToken,您应该获得一个有效的令牌,或者没有。不,它返回
null
。啊!你的会计经理做得不对。它返回的bundle需要有一个KEY_INTENT值,用于命名验证活动。该活动需要获取响应对象(也在bundle中)并调用其onResponse方法。除了正在重新运行的同步外,一切都正常。返回null
是blockingGetAuthToken
记录行为的一部分。实际上,您不必重新运行同步。当blockingGetAuthToken返回时,您应该拥有已验证的帐户。如果验证器工作正常,则仅当帐户无效时,它才会返回null。见: