Android AlarmManager - RTC_WAKEUP vs ELAPSED_REALTIME_WAKEUP

87

Adakah yang bisa menjelaskan kepada saya perbedaan antara AlarmManager.RTC_WAKEUPdan AlarmManager.ELAPSED_REALTIME_WAKEUP? Saya telah membaca dokumentasinya tetapi masih belum benar-benar memahami implikasi penggunaan salah satu dari yang lain.

Kode contoh:

    alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 
                     scheduledAlarmTime, 
                     pendingIntent);

    alarmManager.set(AlarmManager.RTC_WAKEUP, 
                     scheduledAlarmTime, 
                     pendingIntent);

Seberapa berbeda kedua baris kode tersebut akan dieksekusi? Kapan kedua baris kode tersebut dieksekusi relatif satu sama lain?

Saya menghargai bantuan Anda.

Camille Sévigny
sumber

Jawaban:

141

AlarmManager.ELAPSED_REALTIME_WAKEUP type digunakan untuk memicu alarm sejak waktu boot:

alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 600000, pendingIntent);

akan benar-benar membuat alarm berbunyi 10 menit setelah perangkat melakukan booting .

Ada pengatur waktu yang mulai berjalan saat perangkat melakukan boot untuk mengukur waktu aktif perangkat dan ini adalah jenis yang memicu alarm Anda sesuai dengan waktu aktif perangkat.

Padahal, AlarmManager.RTC_WAKEUPakan memicu alarm sesuai dengan waktu jamnya. Misalnya jika Anda melakukannya:

long thirtySecondsFromNow = System.currentTimeMillis() + 30 * 1000;
alarmManager.set(AlarmManager.RTC_WAKEUP, thirtySecondsFromNow , pendingIntent);

ini, sebaliknya, akan memicu alarm 30 detik dari sekarang .

AlarmManager.ELAPSED_REALTIME_WAKEUPjenis ini jarang digunakan dibandingkan AlarmManager.RTC_WAKEUP.

Rejinderi
sumber
1
Itulah yang saya pikir. Saya hanya perlu konfirmasi. Jadi jika saya melakukan sesuatu seperti ini: alarmManager.set (AlarmManager.ELAPSED_REALTIME_WAKEUP, System.currentTimeMills () + 30 * 1000, pendingIntent); hal-hal aneh mungkin terjadi (yang saya alami sampai saya menyadari bahwa itu tidak berfungsi seperti yang saya kira.
Camille Sévigny
2
Harap dicatat bahwa kodenya seharusnya System.currentTimeMillis()bukan System.currentTimeMills():)
HasanAboShally
17
"Jenis AlarmManager.ELAPSED_REALTIME_WAKEUP jarang digunakan dibandingkan dengan AlarmManager.RTC_WAKEUP." Ini spekulasi dan nasihat buruk. Menurut dokumentasi: developer.android.com/training/scheduling/alarms.html "Jika Anda hanya ingin alarm Anda menyala pada interval tertentu (misalnya, setiap setengah jam), gunakan salah satu jenis waktu nyata yang telah berlalu. Dalam umum, ini adalah pilihan yang lebih baik. "
Jared Kells
1
Jawaban @ mborsuk lebih baik dan mengoreksi jawaban ini: Anda tidak boleh menggunakan RTC untuk waktu yang telah berlalu, seperti untuk thirtySecondsFromNow.
Micha F.
2
Penjelasan yang cukup bagus :)! Saya ingin menambahkan komentar penting: sehubungan dengan dokumen resmi dari Android, menggunakan "AlarmManager.ELAPSED_REALTIME_WAKEUP" bisa menjadi sesuatu yang menarik ketika berhubungan dengan aplikasi yang menjalankan permintaan HTTP ke server, dan Anda tidak ingin membuat memuat di server web Anda. Pikirkan tentang ribuan perangkat Android, yang melakukan GET di server web, pada pukul 22.30: karena faktanya berfungsi selama waktu boot perangkat, "AlarmManager.ELAPSED_REALTIME_WAKEUP" dapat membuat "ribuan" permintaan pengaktifan perangkat ini, bukan pada saat yang sama, hindari memuat :).
ivanleoncz
107

Terlepas dari jawaban yang saat ini diterima dan dipilih secara maksimal, jenis AlarmManager.ELAPSED_REALTIME * bersama dengan SystemClock.elapsedRealtime () selalu lebih andal daripada jam RTC untuk alarm dan pengaturan waktu.

Menggunakan ELAPSED_REALTIME_WAKEUP dengan AlarmManager akan bergantung pada jam monotonik yang dimulai dari waktu boot " dan terus berdetak bahkan saat CPU dalam mode hemat daya, begitu juga dasar yang direkomendasikan untuk waktu interval tujuan umum ". Begitu,

alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
                 + 60*1000, pendingIntent);

akan membuat PendingIntent Anda aktif dalam 1 menit (60 * 1000 milidetik).

Sedangkan, AlarmManager.RTC_WAKEUP adalah untuk waktu "dinding" standar dalam milidetik sejak periode tersebut. Begitu,

alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
                 + 60*10000, pendingIntent);

mungkin juga memicu alarm 60 detik dari sekarang, tetapi tidak dapat diandalkan, karena seperti yang dicatat dalam dokumentasi SystemClock :

Jam dinding dapat diatur oleh pengguna atau jaringan telepon (lihat setCurrentTimeMillis (panjang)), sehingga waktu dapat melompat mundur atau maju tanpa terduga. Jam ini hanya boleh digunakan ketika korespondensi dengan tanggal dan waktu dunia nyata penting, seperti di kalender atau aplikasi jam alarm. Pengukuran interval atau waktu yang telah berlalu harus menggunakan jam yang berbeda. Jika Anda menggunakan System.currentTimeMillis (), pertimbangkan untuk mendengarkan siaran Intent ACTION_TIME_TICK, ACTION_TIME_CHANGED dan ACTION_TIMEZONE_CHANGED untuk mencari tahu kapan waktu berubah.

Selain itu, pertanyaannya hanya mereferensikan alarm * _WAKEUP tetapi lihat juga dokumentasi AlarmManager tentang hal itu untuk memastikan Anda memahami apa yang disediakan oleh alarm bangun vs non-bangun.

mborsuk
sumber
Tanggapan Anda bagus, tetapi dalam aplikasi saya, saya perlu menyetel alarm yang bertepatan dengan tanggal / waktu dunia nyata dan bukan hanya 60 detik dari sekarang. Dalam hal ini, RTC_WAKEUP adalah solusi terbaik untuk saya.
Camille Sévigny
8
Tidak apa-apa, tetapi ini adalah jawaban yang lebih akurat untuk pertanyaan dan mengoreksi hal-hal dalam jawaban yang diterima saat ini.
mborsuk
+1 untuk info ini, tetapi perhatikan yang di elapsedRealtime()bawah, SystemClockbukan System. EDIT: ... Batas suara harian tercapai ...
Jorge Fuentes González
Ini adalah salah satu jawaban terbaik untuk masalah ini. Saya sedang mencari jarum di tumpukan jerami setinggi 50m (alias "bug dalam kode saya!"), Dan jawaban Anda membawa saya langsung ke jarum!
AlxDroidDev
17

Hanya sebuah catatan. Anda bisa mendapatkan panggilan milidetik uptime:

long uptimeMillis =  SystemClock.elapsedRealtime();

Jadi jika Anda ingin menyalakan alarm 30 detik dari sekarang, dan Anda ingin menggunakan jam waktu aktif alih-alih jam normal, Anda dapat melakukan:

long thirtySecondsFromNow =  SystemClock.elapsedRealtime() + 30 * 1000;
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, thirtySecondsFromNow, pendingIntent);

Kapan pun Anda ingin memeriksa waktu yang telah berlalu alih-alih tanggal / waktu tertentu, yang terbaik adalah menggunakan waktu aktif. Itu karena waktu saat ini yang disetel oleh pengguna di perangkat dapat berubah jika pengguna mengubahnya menggunakan pengaturan.

Ena
sumber
3
+1 untuk menunjukkan untuk menggunakannya "kapan pun Anda ingin memeriksa waktu yang telah berlalu". Sangat masuk akal.
sulai
Sekali lagi hanya untuk menekankan: pemahaman saya adalah bahwa ini pasti akan menyala 30 detik dari sekarang kecuali terjadi sesuatu seperti perangkat mati. Secara konkret, saya pikir masalah dengan menggunakan RTC_WAKEUP adalah bahwa secara teori, 15 detik dari sekarang, mungkin saja itu menjadi sekitar jam 1 pagi pada hari Sabtu dekat akhir Oktober dan jam sistem mundur 1 jam (di AS dan banyak Eropa, setidaknya), jadi alarm tidak benar-benar terpicu hingga 1 jam 30 detik setelah disetel.
Yannick
2

Saya memprogram masalah ini dalam proyek saya sendiri dengan cara ini. di bawah kode yang saya gunakan

AlarmManager.ELAPSED_REALTIME_WAKEUP

untuk menyetel alarm pada waktu tertentu. variabel 'intentName' digunakan dalam intentFilter untuk menerima alarm ini. karena saya menyalakan banyak alarm jenis ini. ketika saya membatalkan semua alarm. saya menggunakan metode membatalkan. diberikan di bagian bawah.

// untuk menahan alarm dan membatalkan bila diperlukan

     public static ArrayList<String> alarmIntens = new ArrayList<String>();

//

    public static String setAlarm(int hour, int minutes, long repeatInterval,
        final Context c) {
    /*
     * to use elapsed realTime monotonic clock, and fire alarm at a specific time
     * we need to know the span between current time and the time of alarm.
     * then we can add this span to 'elapsedRealTime' to fire the alarm at that time
     * this way we can get alarms even when device is in sleep mood
    */
    Time nowTime = new Time();
    nowTime.setToNow();
    Time startTime = new Time(nowTime);
    startTime.hour = hour;
    startTime.minute = minutes;
    //get the span from current time to alarm time 'startTime'
    long spanToStart = TimeUtils.spanInMillis(nowTime, startTime);
    //
    intentName = "AlarmBroadcast_" + nowTime.toString();
    Intent intent = new Intent(intentName);
    alarmIntens.add(intentName);
    PendingIntent pi = PendingIntent.getBroadcast(c, alarms++, intent,
            PendingIntent.FLAG_UPDATE_CURRENT);
    //
    AlarmManager am = (AlarmManager) c
            .getSystemService(Context.ALARM_SERVICE);
    //adding span to elapsedRealTime
    long elapsedRealTime = SystemClock.elapsedRealtime();
    Time t1 = new Time();
    t1.set(elapsedRealTime);
    t1.second=0;//cut inexact timings, seconds etc
    elapsedRealTime = t1.toMillis(true);

    if (!(repeatInterval == -1))
        am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                elapsedRealTime + spanToStart, repeatInterval, pi);
    else
        am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, elapsedRealTime
                + spanToStart, pi);

dimana fungsi span adalah ini:

 public static long spanInMillis(Time startTime, Time endTime) {
    long diff = endTime.toMillis(true) - startTime.toMillis(true);
    if (diff >= 0)
        return diff;
    else
        return AlarmManager.INTERVAL_DAY - Math.abs(diff);
}

fungsi pembatalan alarm ini.

public static void cancel(Context c) {
    AlarmManager am = (AlarmManager) c
            .getSystemService(Context.ALARM_SERVICE);
    // cancel all alarms
    for (Iterator<String> iterator = alarmIntens.iterator(); iterator
            .hasNext();) {
        String intentName = (String) iterator.next();
        // cancel
        Intent intent = new Intent(intentName);
        PendingIntent pi = PendingIntent.getBroadcast(c, 0, intent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        am.cancel(pi);
        //
        iterator.remove();
    }
}
ahmadalibaloch.dll
sumber
1

Beberapa catatan penting saat memilih alarm mana yang akan digunakan : (untuk siapa yang sudah membaca suara positif)

The RTC_WAKEUP lembah kematian - waktu perubahan:
Jika pengguna memiliki waktu perubahan secara manual ke masa lalu alarm tidak akan pergi, dan masa depan akan menyebabkan alarm untuk pergi segera jika melewati RTCtimestamp.
Jangan gunakan alarm ini untuk melakukan verifikasi sisi klien / pekerjaan penting karena bisa saja gagal.

The WAKEUP makna (Marshmallow dan di atas)
Secara umum - tidak banyak. Tidak akan membangunkan perangkat saat idleatau saat dalam doze, untuk itu alarmManager.setExactAndAllowWhileIdleatau alarmManager.setAndAllowWhileIdle( Istirahatkan & Idle )

Nir Duan
sumber