17

我正在创建一个新的 Android 应用程序SyncAdapter来处理数据库同步。我已经准备好一切,应用程序运行良好,但我注意到我登录了两次。

第一次登录发生在AuthenticatorActivity类(它扩展AccountAuthenticatorActivity)验证用户和密码时。

如果用户名和密码正确,AuthenticatorActivity则执行以下操作:

  • 如果account不存在,它会使用mAccountManager.addAccountExplicitly()
  • authToken保存使用intent.putExtra(AccountManager.KEY_AUTHTOKEN, authToken);

这基本上是从 Android 示例中复制/粘贴的,所以我想没关系。

问题是当SyncAdapter启动和使用

authtoken = mAccountManager.blockingGetAuthToken(account,
          AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, true);

调用扩展类getAuthToken()内部的方法。在这个方法中,我再次点击登录端点。AuthenticatorAbstractAccountAuthenticator

从那时起,在authToken过期之前不会再次点击登录端点。

这不是让我很困扰的事情,但我想知道是否有办法避免登录两次。

4

1 回答 1

15

如您所见,尽管Authenticator.java在 SampleSyncAdapter 中说

此类演示的有趣之处在于将 authTokens 用作身份验证过程的一部分。...如果我们已经在帐户中存储了一个 authToken,我们将返回该 authToken。如果我们没有,但我们确实有用户名和密码,那么我们将尝试与示例服务对话以获取 authToken。

这是一个谎言。 Authenticator.getAuthToken不进行任何缓存检查,它只是通过网络获取令牌。

解决方案是添加缺少的检查:

Authenticator.java:
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
        String authTokenType, Bundle loginOptions) throws NetworkErrorException {

    // check that authToken type supported
    ...

    // Check if we already have a cached token to return
    final AccountManager am = AccountManager.get(mContext);
    String cachedAuthToken = am.peekAuthToken(account, authTokenType);
    if (cachedAuthToken != null) {
        final Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
        result.putString(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
        result.putString(AccountManager.KEY_AUTHTOKEN, cachedAuthToken);
        return result;
    }

    // Get new authToken from server
    ...

    // If all else fails, prompt the user for credentials
    ...
}

请注意,当调用失败时,您的项目的其余部分需要认真使用AccountManager.invalidateAuthToken,否则您将最终导致调用失败的无限循环,尝试获取新的身份验证令牌,然后在返回相同的缓存身份验证令牌时再次失败。

于 2012-07-30T20:24:07.720 回答