60

アプリケーションをGooglePlayにアップロードしましたが、ユーザーから次の例外が報告されています

java.lang.RuntimeException:WakeLockがロックされていないC2DM_LIB。この例外は、を解放しようとすると発生しWakeLockます。何が問題なのか誰かに教えてもらえますか?

4

4 に答える 4

188

コードを投稿しなかったので、ここで提案することをすでに実行したかどうかはわかりませんが、例外もあり、修正するために追加したのは、WakeLockを確認するための単純な「if」だけでした。それを解放しようとする前に、実際に保持されています。

onPauseに追加したのは、この「if」ステートメント(「release()」の前)だけです。

if (mWakeLock.isHeld())
    mWakeLock.release();

そして例外はなくなりました。

于 2013-02-19T03:32:01.280 に答える
64

新しいGCMライブラリでも同じ例外を追跡しました。実際、古いC2DM Androidライブラリにも同じエラー、同じクラッシュがあり、Googleはまだ修正していません。統計からわかるように、ユーザーの約0.1%がこのクラッシュを経験しています。

WakeLock私の調査によると、ライブラリが何も保持していないネットワークを解放しようとしたときに、GCMライブラリのネットワークが正しく解放されないことが問題であることがわかりましたWakeLock(内部ロックカウンターが負になります)。

私は単純な解決策に満足しました-この例外をキャッチして何もしないでください。余分な仕事をする必要がないので、ウェイクロックは何も保持しません。

これを行うには、コンパイル済みのファイルではなく、プロジェクトにGCMライブラリソースをインポートする必要があり.jarます。GCMライブラリソースは「$Android_SDK_Home$ / extras / google / gcm / gcm-client / src」フォルダーにあります(最初にAndroid SDK Managerを使用してダウンロードする必要があります)。

次の開いているGCMBaseIntentServiceクラス、行を見つける

sWakeLock.release();

そしてそれを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");
        }
    }

更新: あるいは、彼の回答で@fastiが示唆しているように、メソッドを使用mWakeLock.isHeld()して、wakelockが実際にこのロックを保持しているかどうかを確認できます。

于 2012-08-27T12:30:57.190 に答える
4

isHeld()ソリューションの方が優れているように見えますが、実際には失敗する可能性があります。これは、アトミックではないため(つまり、スレッドセーフではないため)です。ロックを解放する可能性のあるスレッドが複数ある場合は、チェック(isHeld)と別のスレッドを解放する呼び出しの間にロックが解放される可能性があります...その後失敗します。

try / catchを使用すると、バグを偽装できますが、スレッドセーフな方法で実行できます。

于 2014-06-05T10:39:06.470 に答える
1

ウェイクロックを再初期化せず、新しいオブジェクトで取得を呼び出さない限り、この問題は発生しません。wakeLockのインスタンスは1つだけ保持する必要があります(したがって、フィールド変数にします)。そうすれば、常にその1つのwakeLockを解放していることがわかります。

それで....

 if (mWakeLock == null) {
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
                | PowerManager.ON_AFTER_RELEASE, "MyWakeLock");
    }

try{
        mWakeLock.release();//always release before acquiring for safety just in case
    }
    catch(Exception e){
        //probably already released
        Log.e(TAG, e.getMessage());
    }
    mWakeLock.acquire();
于 2014-07-12T17:33:30.927 に答える