从 AccountManager 中删除帐户不会将用户发送到 AccountAuthenticatorActivity
Removing account from AccountManager doesn't send user to AccountAuthenticatorActivity
我有一个使用 AccountManager 和自定义 AccountAuthenticator 注册用户的应用程序。
我需要实现 Log Out
功能。
当用户单击 Log Out
按钮时,他们的帐户被成功删除,但 activity 保持不变,用户不会被重定向到 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 (has extras) }}]
看来我的 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 为我处理重定向?
当您删除一个帐户时,AccountManager 不会启动另一个帐户设置。如果你想要那种行为,你需要自己实现它。
但是,我不建议以这种方式实施。如果您单击 "log out",您不会期望再次被直接重定向到登录屏幕。
相反,我会显示一条成功消息,如 "Logged out successfully",带有两个按钮,一个显示类似 "Close" 的内容并关闭应用程序,另一个显示类似 "login again" 的内容,它接受用户再次登录屏幕。这对用户更友好,恕我直言。
无论如何,回答你的问题:如果你想自动进入登录屏幕,我看到以下选项:
只需启动帐户设置(使用 AccountManager.addAccount(...)) when the user hits "logout" (optionally remove the account with AccountManager.removeAccountExplicitly(...))。删除(您自己的应用程序的)帐户不太可能失败(尤其是如果您允许 getAccountRemovalAllowed(...)
中的 return true
),因此在大多数情况下,假设删除成功应该是安全的。您的身份验证器必须处理帐户已经存在的情况,因为用户可以随时启动帐户设置。
等待 accountManagerFuture.getResult()
并在 return 成功后像 #1 一样开始帐户设置。
在您的 Activity 中注册一个 OnAccountsUpdateListener using addOnAccountsUpdatedListener(...) 以检查该帐户是否存在。请注意,有三个触发器会导致调用此侦听器:
一个。已创建账号,包括其他应用的账号
b。一个账号被删除,包括其他应用的账号
c。更新了一个账号的密码,也包括其他应用的账号(恕我直言,这个事件应该是认证者私有的,绝对不应该广播)。
但是,回调不会收到任何关于触发器的信息。因此,您需要自行查明您的帐户是否已被删除。
另请注意,您的代码似乎在主线程中调用 accountManagerFuture.getResult()
,这不是一个好主意,因为它可能会阻塞。 AccountManager.removeAccount(...) explicitly says this is not allowed. Even if you're calling it in the AccountManagerCallback
callback and you probably can assume that it's safe to call it I wouldn't rely on it and make sure it's executed in a background thread. If you don't let the user confirm the removal, you probably should call AccountManager.removeAccountExplicitly(...) 的文档代替。
我有一个使用 AccountManager 和自定义 AccountAuthenticator 注册用户的应用程序。
我需要实现 Log Out
功能。
当用户单击 Log Out
按钮时,他们的帐户被成功删除,但 activity 保持不变,用户不会被重定向到 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 (has extras) }}]
看来我的 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 为我处理重定向?
当您删除一个帐户时,AccountManager 不会启动另一个帐户设置。如果你想要那种行为,你需要自己实现它。
但是,我不建议以这种方式实施。如果您单击 "log out",您不会期望再次被直接重定向到登录屏幕。
相反,我会显示一条成功消息,如 "Logged out successfully",带有两个按钮,一个显示类似 "Close" 的内容并关闭应用程序,另一个显示类似 "login again" 的内容,它接受用户再次登录屏幕。这对用户更友好,恕我直言。
无论如何,回答你的问题:如果你想自动进入登录屏幕,我看到以下选项:
只需启动帐户设置(使用 AccountManager.addAccount(...)) when the user hits "logout" (optionally remove the account with AccountManager.removeAccountExplicitly(...))。删除(您自己的应用程序的)帐户不太可能失败(尤其是如果您允许
getAccountRemovalAllowed(...)
中的 returntrue
),因此在大多数情况下,假设删除成功应该是安全的。您的身份验证器必须处理帐户已经存在的情况,因为用户可以随时启动帐户设置。等待
accountManagerFuture.getResult()
并在 return 成功后像 #1 一样开始帐户设置。在您的 Activity 中注册一个 OnAccountsUpdateListener using addOnAccountsUpdatedListener(...) 以检查该帐户是否存在。请注意,有三个触发器会导致调用此侦听器:
一个。已创建账号,包括其他应用的账号
b。一个账号被删除,包括其他应用的账号
c。更新了一个账号的密码,也包括其他应用的账号(恕我直言,这个事件应该是认证者私有的,绝对不应该广播)。
但是,回调不会收到任何关于触发器的信息。因此,您需要自行查明您的帐户是否已被删除。
另请注意,您的代码似乎在主线程中调用 accountManagerFuture.getResult()
,这不是一个好主意,因为它可能会阻塞。 AccountManager.removeAccount(...) explicitly says this is not allowed. Even if you're calling it in the AccountManagerCallback
callback and you probably can assume that it's safe to call it I wouldn't rely on it and make sure it's executed in a background thread. If you don't let the user confirm the removal, you probably should call AccountManager.removeAccountExplicitly(...) 的文档代替。