java.lang.RuntimeException:WakeLock未锁定C2DM_LIB

Roo*_*kie 49 android android-service android-c2dm google-cloud-messaging

我已将我的应用程序上传到谷歌播放,但用户报告了以下异常

java.lang.RuntimeException:WakeLock未锁定C2DM_LIB.当我尝试释放时发生此异常WakeLock.任何人都可以告诉可能是什么问题.

fas*_*sti 159

你没有发布你的代码,所以我不知道你是否已经完成了我将在这里建议的内容,但是我也有这个例外,我添加的所有内容都是一个简单的"if"以确保WakeLock在尝试发布之前,实际上是在举行.

我在onPause中添加的所有内容都是"if"语句(在"release()"之前):

if (mWakeLock.isHeld())
    mWakeLock.release();
Run Code Online (Sandbox Code Playgroud)

而且例外消失了.

  • 这个解决方案对我来说似乎比接受的解决方案更清晰. (7认同)
  • 我同意这应该是已接受的答案,但不要忘记将上面的代码放在同步语句中.在极少数情况下,唤醒锁是由isHeld和release之间的另一个线程释放的. (4认同)
  • 我的代码中没有.release()(没有mWakeLock这么做)但我仍然遇到这个错误.我看到的唯一堆栈跟踪是:java.lang.RuntimeException:在android.app.IntentService $ ServiceHandler上的com.google.android.gcm.GCMBaseIntentService.onHandleIntent(GCMBaseIntentService.java:252)中的WakeLock欠锁定GCM_LIB .handleMessage(IntentService.java:65) (2认同)

Hit*_*sit 55

我也在新的GCM库中跟踪了同样的异常.实际上旧的C2DM Android库有同样的错误,同样的崩溃,谷歌还没有修复它.正如我从统计数据中看到的那样,大约有0.1%的用户遇到了此次崩溃.

我的调查表明问题在于WakeLockGCM库中网络的错误释放,当库试图释放时WakeLock什么都不保留(内部锁定计数器变为负数).

我对简单的解决方案感到满意 - 只是抓住这个例外并且什么都不做,因为我们不需要做任何额外的工作,然后我们的唤醒器什么都不做.

为此,您需要在项目中导入GCM库源,而不是已编译的.jar文件.您可以在" $ Android_SDK_Home $/extras/google/gcm/gcm-client/src "文件夹下找到GCM库源(您需要先使用Android SDK Manager下载它).

下一个公开GCMBaseIntentService课,找到行

sWakeLock.release();
Run Code Online (Sandbox Code Playgroud)

用try-catch包围它.

它应该如下所示:

    synchronized (LOCK) {
        // sanity check for null as this is a public method
        if (sWakeLock != null) {
            Log.v(TAG, "Releasing wakelock");
            try {
                sWakeLock.release();
            } catch (Throwable th) {
                // ignoring this exception, probably wakeLock was already released
            }
        } else {
            // should never happen during normal workflow
            Log.e(TAG, "Wakelock reference is null");
        }
    }
Run Code Online (Sandbox Code Playgroud)

更新: 另外,正如@fasti在他的回答中建议的那样,你可以使用mWakeLock.isHeld()方法来检查唤醒锁是否真的持有这个锁.

  • 这种解决方案很重,可以解决地毯下的问题.下面由fasti提出的是处理它的正确方法. (4认同)
  • 我继续在谷歌的回购中做出这个改变并把它放在Github上:https://github.com/ajlyon/gcm (3认同)

Sho*_*ham 5

尽管 isHeld() 解决方案看起来更好,但它实际上可能会失败 - 因为它不是原子的(即不是线程安全的)。如果您有多个线程可能会释放锁,那么在检查(isHeld)和释放另一个线程的调用之间可能会释放锁......然后您就会失败。

通过使用 try/catch,您可以以线程安全的方式掩盖错误。