原始发布者在维护实例状态时遇到问题的原因可能是因为 Android 的默认行为是为每个新意图启动一个新活动。这就是为什么 GrkEngineer 在 web 回调之后没有看到 onRestoreInstanceState 被调用的原因。
将您的请求令牌存储为共享首选项是一种解决方案,以便可以从 OAuth Web 回调之后启动的新活动中访问它。
我最初尝试使用共享首选项,它似乎工作正常。但是,我认为这不是最好的解决方案。理想情况下,您希望强制 Android 将回调传递给您的原始活动(我将在下面解释原因)。
我尝试使用 singleTask 和 singleInstance 启动模式来部分成功地完成此操作,但感觉不对,Android 文档暗示不建议将这些模式用于一般用途。
经过大量研究文档和测试后,我发现在创建 Intent 时使用以下标志会导致 Android 将 Intent 传递给 Activity 的现有实例(如果它被杀死则重新创建它)。
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
我需要让原始活动处理回调的原因是我可以与 android AccountManager 集成。我使用以下示例开始:
http://developer.android.com/resources/samples/SampleSyncAdapter/index.html
与 AccountManager 身份验证器机制集成的关键部分之一是 AccountAuthenticatorResponse,它被传递到您的活动中以启动身份验证过程。
我发现实现它的一个大问题是保留对 AccountAuthenticatorResponse 对象的引用。这将传递到您的 AuthenticatorActivity 中,一旦身份验证完成,您需要调用它的方法,以便标准帐户 UI 保持正确状态。但是,我遇到了 GrkEngineer 最初遇到的同样问题。当我尝试在 OAuth 回调之后重新启动我的 OAuth 身份验证器活动时,我总是得到一个新实例,该实例丢失了对 AccountAuthenticatorResponse 对象的引用,并且我看不到任何持久化该对象的方法。
关键是使用我上面描述的意图标志。
AuthenticatorActivity 是由我的 AbstractAccountAuthenticator 使用 FLAG_ACTIVITY_NEW_TASK 启动的。它获取请求令牌(使用 AsyncTask)并启动浏览器以请求用户授权。
OAuthCallbackHandlerActivity 已注册以处理我的自定义回调方案。在用户授予访问权限后调用它时,它会使用标志 Intent.FLAG_ACTIVITY_NEW_TASK | 调用 AuthenticatorActivity。 Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP 意图。
这会导致我原来的 AuthenticatorActivity 被重新激活。 AccountAuthenticatorResponse 对象仍然可用(我保存在 OnSaveInstanceState 中的请求令牌/秘密也是如此)。 Activity 现在可以获取访问令牌(再次使用 AsyncTask),然后调用 AccountAuthenticatorResponse 对象的完成方法。
完成这项工作的关键是使用我提到的意图标志,并确保 AuthenticatorActivity 在您的应用程序任务中启动,而不是在帐户管理器任务中启动。 FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_SINGLE_TOP 只会导致活动的现有实例在同一任务中被重用。因此,如果您要返回的活动是在其他任务中启动的,那么原始实例将不会被重用。
我在模拟器上使用开发工具测试了这个,立即终止我的 AuthenticatorActivity,以便我可以测试重新创建过程。将 onSaveInstanceState/onRestoreInstanceState 用于请求令牌/秘密时效果很好。而且我什至不必担心恢复 AccountAuthenticatorResponse 对象。这是由 Android 自己恢复的 - 神奇!