GoogleAuthUtil.getToken()抛出:RuntimeException:无法在未调用Looper.prepare()的线程内创建处理程序

时间:2013-12-16 22:29:40

标签: android google-play-services

此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员工的指导:)

谢谢!

1 个答案:

答案 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()。