4

最近、ユーザーからアラームアプリが鳴らないという情報を受け取っています。最後に、ユーザーの1人がビルドインログから情報を送ってくれましたが、これは本当に奇妙なことでした。

74. 4:25:0 - StartAlarm received
75. 5:22:15 - AlarmOnScreen create
76. 5:22:15 - Time: 04:25

問題は、ログに記録する情報が次のように保存されることです。

//BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent) {
    Logger.initialize(context);
    Logger.log("StartAlarm received");
    Intent i = new Intent(context, AlarmOnScreen.class);
    i.putExtras(intent.getExtras());
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(i);
}

//AlarmOnScreen (activity)
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.alarm_on_screen);
    Logger.log("AlarmOnScreen create");
    //Time value of alarm is logged below
    (...)

ご覧のとおり、活動の開始はかなり遅れました。そんなことがあるものか?ユーザーは、彼が電話を「使い始める」まで、つまり、ロック画面のロックが解除されるか、画面がオンになるまで、アラームが遅れたと報告しました。私はまだより多くの情報で答えを待っています。他の時間の遅延はわずか5分でした-ユーザーが「電話を使い始める」まで毎回

何か案は?

編集:追加させてください、それはアプリケーションが数ヶ月間出ていた後、最近起こり始めたものです。マニフェストと前回のアップデートで何かを変更したかどうかはまだ探していますが、Androidの新しいバージョンでのみ発生する可能性はありますか?

4

2 に答える 2

5

あなたの問題は、WakeLocksを適切に使用せずにAlarmManagerを使用することであると思います。デバイスが画面をオフにして「スリープ」すると、レシーバーが正しく機能しなくなります。

レシーバーがAlarmManagerからonReceive()を取得したと思います。これは、おそらく_WAKEUP次のようなフラグで開始されています。

mAlarmManager.set(AlarmManager.RTC_WAKEUP, .......);

この_WAKEUPフラグは、デバイスがスリープモードであっても、デバイスが「オン」になることを意味します。ただし、ここのドキュメント(http://developer.android.com/reference/android/app/AlarmManager.html)で説明されているように:

アラームマネージャは、アラームレシーバのonReceive()メソッドが実行されている限り、CPUウェイクロックを保持します。これにより、ブロードキャストの処理が終了するまで電話がスリープしないことが保証されます。onReceive()が戻ると、AlarmManagerはこのウェイクロックを解除します。これは、onReceive()メソッドが完了するとすぐに電話がスリープする場合があることを意味します。アラームレシーバーがContext.startService()を呼び出した場合、要求されたサービスが起動される前に電話がスリープする可能性があります。これを防ぐために、BroadcastReceiverとServiceは、サービスが利用可能になるまで電話が実行され続けることを保証するために、個別のウェイクロックポリシーを実装する必要があります。

onReceive()あなたのコードでは、システムが終了するとすぐにスリープ状態に戻り、startActivity(i)同期して動作しないため、上記の問題に直接つながりますが、はるかに後で、ユーザーが向きを変えるときに起動されます画面上の。

それを解決するには、次のようなことをお勧めします。

//BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent) {
    Logger.initialize(context);
    Logger.log("StartAlarm received");
    Intent i = new Intent(context, AlarmOnScreen.class);
    i.putExtras(intent.getExtras());
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(i);
    AlarmOnScreen.acquireLock(context);
    //Before, system could sleep right after this line(not exactly, however) and activity actually would be started much later
}

//AlarmOnScreen (activity)

private static WakeLock sWakeLock;
public static void acquireLock(Context context) {
    PowerManager pm = (PowerManager)  context.getSystemService(Context.POWER_SERVICE);
    sWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "providersLock");
    //Limit 10 sec, if something wrong will happen - we'll not drain the battery to much.
    sWakeLock.acquire(10000); 
    //As we are acquiring and releasing only once - we don't need a counter.
    sWakeLock.setReferenceCounted(false);
}

private static void releaseLock(Context context) {
    try {
        sWakeLock.release();
    } catch (Exception e) {
        //In case it's already auto-released
        e.printStackTrace();
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.alarm_on_screen);
    Logger.log("AlarmOnScreen create");
    //Time value of alarm is logged below
    (...)

@Override
protected void onResume() {
    releaseLock(this);
}

このソリューションは初めて機能し、問題をより深く理解できるようになります。テストするには-画面がオフになっていて、おそらくケーブルが接続されていないときにアラームの使用を開始しますが、デバイスをスリープモードにするために最後のものが本当に必要かどうかはわかりません。

ただし、現在の静的参照の設計は、競合状態では完全に機能しないため、かなり貧弱であるため、プロジェクトに適した、より洗練されたソリューションを実装することを強くお勧めします。

お役に立てば幸いです。ご不明な点がありましたらお知らせください。幸運を。

UPD: PARTIAL_WAKE_LOCKだけでなく、FULLも使用することをお勧めします。好き:

pm.newWakeLock(PowerManager.FULL_WAKE_LOCK 
    | PowerManager.ACQUIRE_CAUSES_WAKEUP, "providersLock");

これにより、新しいアクティビティの作成に対する以前の状態やプラットフォームの反応に依存せずに、とにかく画面が強制的にオンになります。

于 2012-09-11T15:19:53.263 に答える
0

アクティビティウィンドウにいくつかのフラグを設定する必要があります。

getWindow().addFlags(
    WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
    WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
    WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
    WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
);
于 2012-09-07T08:11:31.250 に答える