44

Tôi đã tải lên ứng dụng của tôi trên google play nhưng người dùng đã báo cáo ngoại lệ saujava.lang.RuntimeException: WakeLock dưới khóa C2DM_LIB

java.lang.RuntimeException: WakeLock dưới khóa C2DM_LIB. Ngoại lệ này xảy ra khi tôi cố gắng phát hành WakeLock. Bất cứ ai có thể nói những gì có thể là vấn đề.

Trả lời

51

Tôi đã lần theo cùng một ngoại lệ trong Thư viện GCM mới. Trên thực tế, thư viện Android C2DM cũ có cùng lỗi, cùng một sự cố và Google chưa sửa nó. Như tôi có thể thấy bằng thống kê của chúng tôi, khoảng 0,1% người dùng gặp sự cố này.

Điều tra của tôi cho thấy rằng sự cố đang phát hành không chính xác mạng WakeLock trong thư viện GCM, khi thư viện cố gắng giải phóng WakeLock không giữ gì (bộ đếm khóa nội bộ trở thành âm).

Tôi hài lòng với giải pháp đơn giản - chỉ cần nắm bắt ngoại lệ này và không làm gì cả, bởi vì chúng tôi không cần phải thực hiện thêm bất kỳ công việc nào thì wakelock của chúng tôi không giữ gì cả.

Để thực hiện việc này, bạn cần nhập các nguồn thư viện GCM vào dự án của mình, thay vì tệp đã biên dịch .jar. Bạn có thể tìm nguồn thư viện GCM trong thư mục "$ Android_SDK_Home $/extras/google/gcm/gcm-client/src" (trước tiên bạn cần phải tải xuống thư viện này bằng Trình quản lý SDK Android).

Tiếp theo mở GCMBaseIntentService lớp, tìm dòng

sWakeLock.release(); 

và bao quanh nó với try-catch.

Nó sẽ giống như thế này:

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, như @fasti đề xuất trong his answer, bạn có thể sử dụng mWakeLock.isHeld() phương pháp để kiểm tra xem wakelock thực sự giữ khóa này.

+0

bạn đã thử nó ..? Liệu nó có chạy tốt hay không sau khi thử nó .. – Rookie

+1

Có, tôi đã thực hiện giải pháp này trong tất cả các dự án của chúng tôi, nó hoạt động hoàn hảo (userbase hơn 2 triệu người dùng) – HitOdessit

+0

ok, cảm ơn ..... – Rookie

135

Bạn không đăng mã của mình, vì vậy tôi không biết bạn đã làm những gì tôi sẽ đề xuất ở đây, nhưng tôi cũng có ngoại lệ đó và tất cả những gì tôi thêm vào để khắc phục nó là "if" đơn giản để đảm bảo WakeLock thực sự đang được giữ, trước khi cố gắng giải phóng nó.

Tất cả tôi thêm vào trong onPause của tôi là này "nếu" tuyên bố (trước khi "phát hành()"):

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

và ngoại lệ đã biến mất.

+6

Giải pháp này có vẻ sạch hơn rất nhiều so với giải pháp được chấp nhận. – ottel142

+1

Đó là bởi vì đó là - và - đúng cách để làm điều đó. Điều này đáng lẽ phải là câu trả lời được chấp nhận. – ComputerEngineer88

+0

Tôi không có .release() trong mã của tôi (không có mWakeLock những gì bao giờ hết) nhưng tôi vẫn nhận được lỗi này. Stacktrace duy nhất tôi thấy là: java.lang.RuntimeException: WakeLock bị khóa dưới GCM_LIB tại [...] com.google.android.gcm.GCMBaseIntentService.onHandleIntent (GCMBaseIntentService.java:252) tại android.app. IntentService $ ServiceHandler.handleMessage (IntentService.java:65) – Ted

3

Mặc dù giải pháp isHeld() có vẻ đẹp hơn, nhưng nó thực sự có thể thất bại - bởi vì nó không phải là nguyên tử (tức là không an toàn). Nếu bạn có nhiều hơn một luồng có thể giải phóng khóa thì giữa dấu kiểm (isHeld) và lệnh gọi lại chuỗi khác có thể giải phóng khóa ... và sau đó bạn thất bại.

Bằng cách sử dụng thử/bắt bạn ngụy trang lỗi, nhưng theo cách an toàn.

+0

Có một lựa chọn tốt để làm cho một bản phát hành WakeLock nguyên tử một cách tái sử dụng? Nó phải là một hoạt động nguyên tử. Nó theo nghĩa đen có "Lock" trong tên. – colintheshots

1

Tôi không gặp vấn đề này miễn là tôi không khởi động lại khóa đánh thức và cuộc gọi có được trên đối tượng mới. Bạn chỉ nên giữ một thể hiện của wakeLock (do đó biến nó thành một biến trường). Sau đó, bạn biết bạn luôn luôn phát hành một wakeLock đó.

Vì vậy ....

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(); 
Các vấn đề liên quan