答えて

51

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

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

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

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

次オープン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"); 
     } 
    } 

UPDATE: Alternativallyを、his answerに@fasti示唆されているように、あなたはwakelockが実際にこのロックを保持しているかどうかを確認するためにmWakeLock.isHeld()メソッドを使用することができます。

+0

は、あなたがそれを試してみましたか..? – Rookie

+1

はい、私はすべてのプロジェクトでこのソリューションを実装しましたが、それは完全に動作します(2Mユーザー以上のユーザベース) – HitOdessit

+0

ok、ありがとう..... – Rookie

135

あなたはコードを投稿していないので、私がここで示唆したことを既にしているかどうかわかりませんが、 でも例外がありました。 を解放しようとする前に、WakeLockが実際に保持されていることを確認してください。

私はonPauseに追加されたすべてが、この "IF" 文は( "リリース()" の前)であった:

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

と例外が消えていました。

+6

この解決策は、受け入れられたものよりも私にとってはきれいだと思われます。 – ottel142

+1

これは、それが正しい方法であるからです。これは受け入れられた答えだったはずです。 – ComputerEngineer88

+0

私のコードに.release()はありませんが(mWakeLockはそれほどありません)、まだこのエラーが発生しています。表示される唯一のスタックトレースは次のとおりです。 java.lang.RuntimeException:アンロックされたWakeLock GCM_LIB [...] com.google.android.gcm.GCMBaseIntentService.onHandleIntent(GCMBaseIntentService.java:252) android.app IntentService $ ServiceHandler.handleMessage(IntentService.java:65) – Ted

3

isHeld()ソリューションはより良いようですが、実際には失敗する可能性があります。アトミックではない(スレッドセーフではない)ためです。ロックを解除する可能性のあるスレッドが複数ある場合、チェック(isHeld)と別のスレッドをrelaseする呼び出しがロックを解除して失敗する可能性があります。

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

+0

再利用可能な方法でWakeLockリリースをアトミックにする良い選択肢はありますか?これはアトミックな操作でなければなりません。それは文字通りその名前に "Lock"を持っています。 – colintheshots

1

私はウェイクロックを再初期化せずに新しいオブジェクトでacquireを呼び出す限り、この問題はありません。 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(); 
関連する問題

 関連する問題