我有一个使用AccountManager和自定义AccountAuthenticator注册用户的应用程序。
我需要实现Log Out
功能。
当用户点击Log Out
按钮时,他们的帐户会被成功删除,但活动保持不变,用户无法重定向到AccountAuthenticatorActivity
,但如果我关闭应用并再次打开它,它将显示身份验证屏幕(即帐户实际已被删除)。
我是否必须自己执行重定向(使用finish(); startActivity(...);
),或者Authenticator和AccountManager应该为我处理它(因为我认为如果它被声明为服务,它应该)?
也许我必须实现某种帐户删除监听器?
无论如何,这是我在MainActivity
中删除帐户的方式:
private void performLogout() {
Account[] accounts = accountManager.getAccountsByType(AccountGeneral.ACCOUNT_TYPE);
if (accounts.length != 0) {
accountManager.clearPassword(accounts[0]);
accountManager.invalidateAuthToken(AccountGeneral.ACCOUNT_TYPE,
accountManager.getAuthToken(accounts[0], AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, null, true,
accountManagerFuture -> {
try {
Log.d("invalidateAuthToken", accountManagerFuture.getResult().toString());
} catch (android.accounts.OperationCanceledException | AuthenticatorException | IOException e) {
e.printStackTrace();
}
}, null).toString());
if (Build.VERSION.SDK_INT < 23) { // use deprecated method
accountManager.removeAccount(accounts[0], accountManagerFuture -> {
try {
if (accountManagerFuture.getResult()) {
Log.d("Deprecated ACCOUNT REMOVAL", "ACCOUNT REMOVED");
}
} catch (android.accounts.OperationCanceledException | IOException | AuthenticatorException e) {
e.printStackTrace();
}
}, null);
} else {
accountManager.removeAccount(accounts[0], this, accountManagerFuture -> {
try {
if (accountManagerFuture.getResult() != null) {
Log.d("ACCOUNT REMOVAL", "ACCOUNT REMOVED");
}
} catch (android.accounts.OperationCanceledException | AuthenticatorException | IOException e) {
e.printStackTrace();
}
}, null);
}
}
}
顺便说一句,当我点击Log Out
时,我可以在日志中看到以下行:
D / invalidateAuthToken:Bundle [{intent = Intent {cat = [2] cmp = discounty.com / .activities.LoginActivity(有额外内容)}}]
所以似乎我的LoginActivity
(AccountAuthenticatorActivity)实际上想要出现,但有些事情阻止它这样做。
在我的自定义AccountAuthenticator
中,我实施了此方法(以及其他一些负责创建帐户和令牌的方法):
@Override
public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, Account account) throws NetworkErrorException {
Bundle bundle = new Bundle();
boolean allowed = true;
bundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, allowed);
return bundle;
}
在我的清单中,我按以下方式声明了服务:
<service
android:name=".authenticator.DiscountyAuthenticationService"
android:process=":auth">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
那么,我是否必须手动重定向用户,或者我需要改进代码中的某些内容以使AccountManager为我处理重定向?
答案 0 :(得分:3)
删除帐户时,AccountManager不会启动其他帐户设置。如果您想要这种行为,您需要自己实现它。
但是,我不建议以这种方式实施。如果单击“注销”,则不希望再次直接重定向到登录屏幕。
相反,我会通过两个按钮显示成功消息,例如“已成功注销”,一个显示“关闭”并关闭应用程序,另一个显示“再次登录”,将用户带到登录屏幕再次。这更加用户友好,恕我直言。
无论如何,要回答你的问题:如果你想自动进入登录界面,我会看到以下选项:
只需在用户点击“退出”时启动帐户设置(使用AccountManager.addAccount(...))(可选择删除AccountManager.removeAccountExplicitly(...)帐户)。删除(您自己的应用程序)的帐户不太可能失败(特别是如果您允许在true
中返回getAccountRemovalAllowed(...)
),因此在大多数情况下,假设删除成功应该是安全的。您的身份验证者必须处理该帐户已存在的情况,因为用户可以随时启动帐户设置。
等待accountManagerFuture.getResult()
并启动帐户设置,就像在#1中返回成功一样。
在您的活动中使用OnAccountsUpdateListener注册addOnAccountsUpdatedListener(...),以检查该帐户是否存在。请注意,有三个触发器会调用此侦听器:
一个。已创建帐户,包括其他应用的帐户
湾帐户已被删除,包括其他应用的帐户
℃。帐户的密码已更新,还包括其他应用程序的帐户(恕我直言,此事件应该是验证者专用的,绝对不应该广播)。
但是,回调函数不会收到触发器的任何信息。因此,如果您的帐户已被删除,您需要了解自己。
另请注意,您的代码似乎在主线程中调用accountManagerFuture.getResult()
,这不是一个好主意,因为它可能会阻塞。 AccountManager.removeAccount(...)的文档明确表示不允许这样做。即使你在AccountManagerCallback
回调中调用它,你可能会认为调用它是安全的,我不会依赖它并确保它在后台线程中执行。如果您不让用户确认删除,您可能应该拨打AccountManager.removeAccountExplicitly(...)。