2013-03-25 182 views
0

我有一個報警應用程序,並被用戶聯繫,他報告說他的報警有時會延遲。我嘗試過不同的方法和理論,最後建議用戶使用默認的Android鬧鐘作爲備份。帶PARTIAL_WAKE_LOCK的WakeLock無法正常工作

通常報警延遲了大約一個小時,但是最後一次我的報警剛剛發生在Android的一個明確的建議之後,那個設備就睡着了,並且被Android的報警喚醒,從而允許我的「繼續啓動」。

編輯: 由於我修改了一些類,並且已經收到來自新版本的日誌,因此我正在更改下面的類和日誌信息。

以下是我正在使用的CountedWakeLock類 - 我創建了自己的HandlerThread來處理喚醒鎖的延遲釋放,以檢查是否會影響啓動問題。它沒有解決問題,但它在日誌(下面)中產生了有趣的信息。

public class CountedWakeLock { 

private static long TIMEOUT_DEFAULT = DateUtils.MINUTE_IN_MILLIS * 3; 
private static WakeLock sWakeLock = null; 
private static int sLockCount; 

private static class TimeoutReleaseThread extends HandlerThread { 

    static TimeoutReleaseThread mInstance = null; 

    Handler mHandler; 
    private Runnable mReleaseRunnable; 

    public static TimeoutReleaseThread instance() { 
     if (mInstance == null) mInstance = new TimeoutReleaseThread(); 
     return mInstance; 
    } 

    public TimeoutReleaseThread() { 
     super("TimeoutReleaseThread HandlerThread"); 
     start(); 
     mHandler = createHandler(); 
     mReleaseRunnable = new Runnable() { 

      @Override 
      public void run() { 
       Utils.log("TimeoutReleaseThread release lock"); 
       releaseLock(); 
      } 
     }; 
    } 

    private synchronized Handler createHandler() { 
     return new Handler(getLooper()); 
    } 

    public synchronized void postRelease(long timeout) { 
     mHandler.removeCallbacks(mReleaseRunnable); 
     mHandler.postDelayed(mReleaseRunnable, timeout); 
    } 
} 

public synchronized static void acquireLock(Context context) { 
    acquireLock(context, TIMEOUT_DEFAULT); 
} 

public synchronized static void acquireLock(Context context, long timeout) { 
    if (sWakeLock == null) { 
     Utils.log("WakeLock creating"); 
     PowerManager pm = (PowerManager) context.getApplicationContext() 
       .getSystemService(Context.POWER_SERVICE); 
     sWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 
       "AlarmReceiver lock"); 
     sWakeLock.setReferenceCounted(false); 
     sLockCount = 0; 
    } else if (sWakeLock.isHeld()) 
     Utils.log("WakeLock held already"); 
    else 
     Utils.log("WakeLock not held"); 

    Utils.log("WakeLock acquiring for " + timeout); 
    sLockCount++; 
    sWakeLock.acquire(); 
    TimeoutReleaseThread.instance().postRelease(timeout); 
} 

public synchronized static void releaseLock() { 
    Utils.log("WakeLock releasing"); 
    if (sWakeLock == null) { 
     Utils.log("WakeLock==null"); 
    } else if (!sWakeLock.isHeld()) { 
     Utils.log("WakeLock not held"); 
     sWakeLock = null; 
     sLockCount = 0; 
    } else { 
     sLockCount--; 
     if (sLockCount <= 0) { 
      Utils.log("WakeLock released"); 
      sWakeLock.release(); 
      sWakeLock = null; 
      if (sLockCount != 0) Utils.log("lockcount=" + sLockCount); 

     } 
    } 
} 
} 

AlarmReceiver廣播接收器 - 它是從AlarmManager

public void onReceive(Context context, Intent intent) { 
    Logger.initialize(context, "AlarmReceiver"); 
    if (CALL_IS_ON) { 
     //set another alarm with AlarmManager to start after 5 seconds 
     //doesn't happen in this situation 
    } else { 
     Utils.log("sending START ALARM"); 
     CountedWakeLock.acquireLock(context); 
     Intent i = new Intent(); 
     i.setAction(StartAlarmReceiver.ACTION_START_ALARM); 
     i.putExtras(intent.getExtras()); 

     context.sendOrderedBroadcast(i, null); //it is ordered, so eventual previous Alarm Activities etc. can be stopped 
     Utils.log("START ALARM send"); 
    } 
} 

StartAlarmReceiver接收意圖。它實際上是啓動報警活動

public void onReceive(Context context, Intent intent) { 
    Logger.initialize(context, "StartAlarmReceiver"); 
    Intent i = new Intent(context, AlarmOnScreen.class); 
    Bundle extras = intent.getExtras(); 
    i.putExtras(extras); 
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
    context.startActivity(i); 
    Utils.log("AlarmActivity started"); 
} 

更新日誌:

504. 27/3 5:0:0 - logger initialized again from AlarmReceiver 
505. 27/3 5:0:0 - sending START ALARM 
506. 27/3 5:0:0 - WakeLock creating 
507. 27/3 5:0:0 - WakeLock acquiring for 180000 
508. 27/3 5:0:0 - START ALARM send 
509. 27/3 5:0:0 - logger initialized again from StartAlarmReceiver 
510. 27/3 5:0:0 - AlarmActivity started 
511. 27/3 5:0:0 - Main start 
512. 27/3 5:0:1 - Main resume 
513. 27/3 5:0:1 - Main pause 
514. 27/3 5:0:5 - Main stop 
515. 27/3 5:3:0 - TimeoutReleaseThread release lock 
516. 27/3 5:3:0 - WakeLock releasing 
517. 27/3 5:3:0 - WakeLock released 
518. 27/3 6:46:18 - logger initialized again from AlarmOnScreen create //user said he unlocked phone then to check the time... 

從日誌現在我相信,激活鎖定實際工作 - 畢竟CPU必須一直運行,如果TimeoutReleaseThread能完成加工。

問題是爲什麼AlarmOnScreen Activity未啓動?爲什麼主要活動(511-514行)已經開始?最近我讓AlarmOnScreen在manifest中設置了singleTask模式。這可能會導致問題嗎?但爲什麼?我需要這個單一任務的其他幾個原因...

設備是GT-S5830i與2.3.6 Android。

回答

0

我仍然不知道是什麼導致了這個問題,但是如果有人會經歷類似的 - 經過多次測試,這只是一個簡單的改變 - 將Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED添加到StartAlarmReceiver中的Intent中。

所以它就像

i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 
    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 

是否行得通?是的,它確實。到目前爲止,它並沒有在其他手機上造成任何問題。

它有道理嗎?一點都不。