此GoogleAuthUtil getToken()调用:
String token = GoogleAuthUtil.getToken(appContext, accountName, scope);
偶尔会因此例外而失败:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare():
ak: GooglePlayServicesNotAvailable
at com.google.android.gms.auth.GoogleAuthUtil.a(Unknown Source)
at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
所以(duh)显然有些东西是谷歌的代码试图创建一个Handler :)但是我们从标准(非Looper)线程调用getToken(),并且每个Google's documentation具有所有建议的异常处理文档明确说明了“如何在阻塞的非主线程上下文中使用GoogleAuthUtil的示例”。所以例如它肯定不应该在UI线程上调用。
有一件事在gplay文档中含糊不清:我们正在将应用程序上下文传递给getToken(),但文档并未说明它是否需要特定的上下文,例如来自一项活动。其他人都有这样或那样的经历吗?我不知道这怎么会导致问题,但你永远不知道。
主要问题:如何恢复?目前我们捕获异常并放弃,但这确实意味着我们未能为受影响的用户获取身份验证。
一如既往地欢迎来自Google员工的指导:)
谢谢!
答案 0 :(得分:4)
我想我们已经弄明白了。 RuntimeException来自getErrorDialog(),同时处理GooglePlayServicesAvailabilityException;关于异常处理的一些事情是从堆栈跟踪中排除它。这就是为什么失败是如此罕见 - 只有不寻常的设备配置抛出异常。
错误:就像Google的文档示例一样,我们的处理程序执行了此操作:
} catch (GooglePlayServicesAvailabilityException e) {
int errorCode = e.getConnectionStatusCode();
if (GooglePlayServicesUtil.isUserRecoverableError(errorCode)) {
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(errorCode, resolutionActivity, ...);
但是这不起作用,因为你不能在非Looper线程上调用getErrorDialog()。
<强> FIX 强>:
Activity resolutionActivity = ...;
try {
String token = GoogleAuthUtil.getToken(appContext, accountName, scope);
...
} catch (GooglePlayServicesAvailabilityException e) {
final int errorCode = e.getConnectionStatusCode();
if (GooglePlayServicesUtil.isUserRecoverableError(errorCode)) {
resolutionActivity.runOnUiThread(new Runnable() {
@Override public void run() {
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(errorCode, resolutionActivity, ...);
errorDialog.show();
我会在发布之后更新并确认它是原因,但似乎很可能。
如果这是问题,那么Google的文档应该更新,因为它显示在后台线程上调用getErrorDialog()。
我们发布了上述修复程序并解决了问题:应在UI线程上调用GooglePlayServicesUtil.getErrorDialog()。