AlarmManager non funziona su diversi dispositivi


85

La mia app utilizza AlarmManager e funziona da 4 anni fa. Ma ho notato che ha iniziato a fallire in alcuni dispositivi.

Sono abbastanza sicuro che il codice sia corretto (sto usando WakefulBroadcastReceiver e setExactAndAllowWhileIdle per i dispositivi con Doze) perché funziona perfettamente sui dispositivi Nexus, ma fallisce nei dispositivi di alcuni produttori (Huawei, Xiaomi ...).

I dispositivi Huawei, ad esempio, hanno una sorta di gestore della batteria che uccide le app e quando un'app viene terminata, gli allarmi programmati vengono annullati. Quindi impostare un'app come "protetta" nel gestore della batteria Huawei risolve il problema.

Ma recentemente ho notato che non funziona con più dispositivi: Xiaomi, Samsung (forse è legato al nuovo "Smart Manager"?) ... Sembra che questo comportamento stia diventando uno standard: uccidere le app in background.

Qualcuno ne sa niente? Qualche modo per garantire che l'allarme venga attivato?

EDIT: Questo problema è causato da "risparmiatori di batteria" aggiunti da diversi produttori. Maggiori informazioni qui: https://dontkillmyapp.com/


8
I produttori incolpano le app per il consumo energetico e continuano a commercializzare gli Octa-core che consumano più batteria rispetto alla CPU con meno core. Pensano che la semplice aggiunta di un core velocizzerebbe i loro telefoni?
FrozenFire

1
@AviLevinshtein Forse ho frainteso la tua domanda. Sto creando gli allarmi nella mia attività. Quindi, quando l'allarme suona, viene eseguito un ricevitore di trasmissione e, infine, viene eseguito un WakefulIntentService (classe da @commonsware).
Sergio Viudes

2
@ JFValdes sto ancora cercando una soluzione. AlarmManager funziona perfettamente sui dispositivi con Android Vanilla. Il problema è che i produttori stanno cercando di "migliorare" le funzionalità Android e hanno rotto AlarmManager ... I produttori non dovrebbero implementare i propri "risparmiatori di batteria", se usano la modalità Doze standard, AlarmManager funzionerebbe perfettamente ... per una soluzione ...
Sergio Viudes

1
C'è ancora una soluzione? Come fanno altre app come promemoria o qualcosa del genere? Ci deve essere un'altra opzione oltre a setAlarm, che è per gli allarmi, non per i promemoria
kv1dr

1
@SergioViudes Sto anche affrontando lo stesso problema con i dispositivi Xiomi per il monitoraggio. e se tengo fuori la mia app dalla limitazione del risparmio della batteria rispetto a quando funziona correttamente in 3 dispositivi su 4, eseguendo le seguenti impostazioni: -> Vai alla batteria -> Alimentazione -> Risparmio batteria app -> la tua app Ora seleziona Nessuna restrizione (per le impostazioni dello sfondo), quindi l'opzione Consenti per la posizione dello sfondo
Imran Khan Saifi

Risposte:


17

Sto cercando di risolverlo già da diverse settimane. Non ho trovato niente. Huawei uccide tutti gli allarmi dopo un po 'di tempo. Se metto l'app nell'app protetta nel risparmio batteria, non aiuta. Ma se cambio il nome del pacchetto della mia app per contenere parole come sveglia, orologio o calendario, funziona in modo assolutamente normale come su qualsiasi altro dispositivo. Non capisco come Google possa fornire la certificazione per questa merda. Penso che l'OEM non dovrebbe modificare la piattaforma principale in questo modo. Capisco che hanno un proprio salvadanaio che uccide l'app dopo un po 'di tempo, quando l'utente non la usa. Ma questo uccide gli allarmi anche delle app protette.

Inoltre, impostareAlarmClock () per gli allarmi con tempismo esatto aiuta. Ma non è possibile usarlo per pensare come l'aggiornamento dei widget.

Aggiornamento: la protezione in base alle parole chiave del nome del pacchetto non funziona già sugli attuali dispositivi Huawei, era vero nel 2017.


Come me, lo provo anche io ma non c'è modo di risolvere questo problema su alcune marche Xiaomi, Oppo, Huawei. A volte interrompono il processo in background e l'allarme per risparmiare batteria.
Andi Susilo

1
Ho un telefono huawei, cambiare il nome del pacchetto in allarme / calendario non fa nulla. L'unico modo per aggirare questo aggiungere la tua app nell'elenco delle app protette dal gestore del telefono
Ashish Pardhiye

9

Il problema è Smart Manager. Samsung ha un gestore della batteria che a volte disabilita l'esecuzione di alcune app in background. Ha provato a "riprendere" quando si torna all'app, ma disabilita completamente l'applicazione o può riprenderla ogni 5 minuti circa (a seconda di come Samsung ce l'ha).

Questo funzionerebbe sulle versioni stock di Android in quanto non esiste un Samsung Manager. Puoi anche installare la versione personalizzata di Android che ha alcune funzionalità per abilitare SM (a seconda della rom).


Sto impazzendo perché non ho un dispositivo Samsung per provarlo. So solo cosa mi dicono gli utenti della mia app. Sai se il problema è che AlarmManager non funziona perché l'app viene interrotta? O il problema è che il dispositivo non può riattivarsi quando l'allarme suona a causa di quel gestore?
Sergio Viudes

@SergioViudes Recentemente molte aziende hanno implementato il proprio. Come LG ne ha uno che funziona in modo simile a Samsung, forse il tuo telefono ne ha uno? Il problema non è l'allarme, l'app di allarme viene spinta in uno stato in cui è completamente inattiva. Smart Manager pensa che sia solo un'app casuale che non ti serve. Ho notato che alcune app possono superarlo, forse alcune app sono accettate dal gestore intelligente.
SA

1
@SergioViudes Ho un Samsung da testare e posso dirti che non puoi ottenere molto da esso. Quando il gestore intelligente ottimizza la tua app non ci sono errori o altro, muore semplicemente, simile all'arresto forzato. Tuttavia è ancora nell'elenco delle app recenti
Tim,

Grazie Tim. Sarebbe fantastico risolvere questo problema senza dover escludere app da "Smart" Manager.
Sergio Viudes

dispositivi come xiaomi (miui), vivo e htc impostano un sacco di autorizzazioni come false per impostazione predefinita, a meno che non si tratti di un'app nell'elenco di app "attendibili" che sembrano determinare da sole (whatsapp, truecaller, ecc. sono attendibili per impostazione predefinita ). Questo sta diventando un incubo dei programmatori
desidigitalnomad

4

La maggior parte dei moderni dispositivi Android è dotata di un'app o di un meccanismo, che cerca automaticamente di capire come risparmiare la batteria e, di conseguenza, potrebbe uccidere alcune app di terze parti. Ciò potrebbe comportare la rimozione di attività e lavori pianificati (ad esempio, allarmi non attivati, notifiche push non funzionanti, ecc.). In molti casi ciò avviene in modo completamente indipendente dai meccanismi di risparmio della batteria di Android, nel mio caso non potrei fare di più l'ottimizzazione della batteria quando rilevo alcuni modelli di dispositivi, reindirizzo l'utente allo start up manager per autorizzare la mia applicazione

Hai trovato in questo collegamento per ogni modello l'intento che dovresti invocare https://android-arsenal.com/details/1/6771


2

Usa AlarmManager per dispositivi <5.0 e JobScheduler per dispositivi 5.0+. Non posso dire con certezza che JobScheduler non sarà influenzato dagli imbrogli del produttore, ma mi sembrerebbe molto meno probabile, dato che Android sta cercando di spostare le persone da AlarmManager e su JobScheduler.

EDIT: Google è uscito con una soluzione di prima parte a questo problema chiamata WorkManager . Astrae più framework di pianificazione e utilizza quello più appropriato per il dispositivo.


2
Sfortunatamente, a differenza della classe AlarmManager, i tempi non sono esatti quando si utilizza JobScheduler. Nella mia app, il tempismo dovrebbe essere esatto :(
Sergio Viudes

Ho provato e alcuni ottimizzatori (almeno Samsung) uccidono tutte le attività in sospeso in JobScheduler quando lo schermo si spegne. Quindi è anche rotto. Questo accade su 5.0. Dopo l'aggiornamento a 6.0 funziona bene, immagino che l'abbiano risolto. Non ho ancora potuto testarlo con altri produttori.
Sloy

Per un tempismo esatto non è possibile utilizzare un servizio in background o un servizio pianificato. Potresti provare un servizio in primo piano, ma questo creerà una notifica persistente per l'utente (probabilmente indesiderabile) e alcuni telefoni hanno degli assassini di attività incorporati che distruggeranno automaticamente il servizio in primo piano. WorkManager è la soluzione migliore ma sfortunatamente non ti darà i tempi esatti.
Tom il

1

Ho anche un'app che imposta gli allarmi. La soluzione è usare AlarmManager.setAlarmClock () su api> = 21. Questo non è influenzato da doze afaik e ha il vantaggio aggiuntivo di mettere un'icona di sveglia nella barra delle applicazioni.


Grazie per la tua risposta. C'è un modo per rimuovere l'icona della sveglia?
Sergio Viudes

Sfortunatamente, setAlarmClock a volte non funziona. L'ho testato su un dispositivo Oreo con poca memoria.
Boris Salimov

1

Potrebbe essere tardi, ma spero che aiuti qualcuno.

Sono rimasto bloccato sullo stesso problema per così tanto tempo. Ma ora so come risolvere questo problema. Questo è per chiunque possa avere lo stesso problema. La gente continua a dire che devi abilitare l' AutoStart ma ci sono riuscito senza usare l'avvio automatico.

Prima di tutto, WakeFullBroadcastaReceiver è ora deprecato e dovresti usare BroadcastReceiver. Secondo, devi usare ForegroudService invece di BackgroundService.

Ti darò l'esempio di seguito:

IntentService.class

public class NotificationService extends IntentService {


//In order to send notification when the app is close
//we use a foreground service, background service doesn't do the work.



public NotificationService() {
    super("NotificationService");
}

@Override
public void onCreate() {
    super.onCreate();

}

@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    //There is no difference in the result between start_sticky or start_not_sticky at the moment
    return START_NOT_STICKY;
}

@Override
protected void onHandleIntent(@Nullable Intent intent) {

    //TODO check if the app is in foreground or not, we can use activity lifecyclecallbacks for this

    startForegroundServiceT();
    sendNotification(intent);
    stopSelf();
}


/***
 * you have to show the notification to the user when running foreground service
 * otherwise it will throw an exception
 */
private void startForegroundServiceT(){

    if (Build.VERSION.SDK_INT >= 26) {
        String CHANNEL_ID = "my_channel_01";
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                "Channel human readable title",
                NotificationManager.IMPORTANCE_DEFAULT);

        ((NotificationManager) 
   getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);

        Notification notification = new Notification.Builder(this, CHANNEL_ID)
                .setContentTitle("")
                .setContentText("").build();

        startForeground(1, notification);
    }
}

private void sendNotification(Intent intent){

    //Send notification
    //Use notification channle for android O+
}
}

avviare il servizio in primo piano in BroadcastReceiver.class

public class AlarmReceiver extends BroadcastReceiver {


@Override
public void onReceive(Context context, Intent intent) {


    Intent service = new Intent(context, NotificationService.class);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(service);
    } else {
        context.startService(service);
    }

}
}

E il setAlarms come questo:

 public static void setAlarm(Context context, int requestCode, int hour, int minute){


    AlarmManager alarmManager =( AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context//same activity should be used when canceling the alarm
            , AlarmReceiver.class);
    intent.setAction("android.intent.action.NOTIFY");

    //setting FLAG_CANCEL_CURRENT makes some problems. and doest allow the cancelAlarm to work properly
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1001, intent, 0);

    Calendar time = getTime(hour, minute);

    //set Alarm for different API levels
    if (Build.VERSION.SDK_INT >= 23){
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
    }
    else{
        alarmManager.set(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
    }

Quindi devi dichiarare il destinatario e il servizio in primo piano nel manifest.

       <receiver android:name=".AlarmReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.NOTIFY">

            </action>
        </intent-filter>
    </receiver>
    <service
        android:name=".NotificationService"
        android:enabled="true"
        android:exported="true"></service>

Spero che questo aiuti qualcuno.


ma nessuno sta dando un voto positivo? @ keivan.k
gumuruh

0

la maggior parte dei nuovi telefoni al giorno d'oggi sono forniti in bundle con una sorta di gestore di risparmio energetico / batteria che fa la stessa cosa che hai descritto. senza contare i dubooster e i clean master.

Penso che sia necessario inserire una dichiarazione di non responsabilità o una domanda frequente nella scheda dell'app / Play Store in cui si afferma che questa app deve essere esclusa dall'app di gestione della batteria per funzionare correttamente.


Ci dovrebbe essere un altro modo per farlo ... Gli utenti non leggeranno il disclaimer. Non riesco a pensare che i telefoni Samsung non consentano alle app di utilizzare AlarmManager ...
Sergio Viudes

Gli allarmi non scatteranno "in tempo", ma alla fine lo faranno
Gavriel

Questa è (purtroppo) la risposta più utile, direi. Vorrei che ci fosse una soluzione migliore, ma i produttori di hardware stanno danneggiando Android vanilla perfettamente funzionante.
caw

0

ho smesso di usare AlarmManager qualche tempo fa ... un'alternativa migliore e più stabile

  1. creare un servizio
  2. registra un BroadcastReceiver per BOOT_COMPLETED
  3. licenzia il tuo servizio dal ricevitore
  4. avvia un nuovo gestore all'interno del tuo servizio che si ripete automaticamente ogni X minuti ( Android - eseguendo un metodo periodicamente utilizzando la chiamata postDelayed () )
  5. controlla se è arrivato il momento di eseguire l'attività: now - tempo di esecuzione> 0 ( come trovare la durata della differenza tra due date in java? )
  6. in tal caso .. eseguire l'attività e arrestare il gestore

sì .. è un dolore .. ma il lavoro viene svolto NON IMPORTA COSA


3
Grazie per il tuo suggerimento, ma vorrei evitare questo approccio, perché l'utilizzo di AlarmManager non consumerà RAM o alcuna risorsa. E se la tua app viene interrotta, il servizio si interromperà, giusto?
Sergio Viudes

non ho detto che questo approccio è BOOLETPROOF, ma almeno è costituito da diverse versioni di API :)
ymz

1
Per funzionare in modo affidabile questa soluzione probabilmente avrebbe bisogno anche di utilizzare i wakelock e ciò consumerebbe enormi quantità di batteria.
Paweł Nadolski

Immagino che tu abbia ragione su questo .. l'unica domanda è: cosa sarebbe peggio - codice inaffidabile o cattive prestazioni? Comunque, io personalmente penso che ci sono modi alternativi per la serratura che può essere adatto in alcuni casi (per esempio: stackoverflow.com/questions/5346694/... )
YAMZ

ma il meccanismo principale - il ricevitore delle emittenti - non si chiama \
Noor Hossain

0

Stai ascoltando BOOT_COMPLETED? È necessario impostare di nuovo gli allarmi quando un dispositivo viene riavviato.


Sì. Come ho detto, gli allarmi funzionavano dal 2012, fino ad ora. Quando il dispositivo viene riavviato, riprogramma gli allarmi nel ricevitore di trasmissione BOOT_COMPLETED.
Sergio Viudes

1
Richiedere un riavvio affinché la tua app funzioni di nuovo non è nemmeno la metà della soluzione
Tim

1
@TimCastelijns non è affatto quello che sto dicendo. SE il dispositivo viene riavviato, tutti gli allarmi impostati con Alarm Manager devono essere reimpostati.
Tyler Pfaff

@TylerPfaff sì, ma il riavvio del dispositivo non è correlato al problema in questa domanda
Tim

0

Quale versione di Android utilizzano questi dispositivi?

A partire dall'API 23, il sistema operativo stesso entrerà in una modalità di inattività a basso consumo quando non viene utilizzato per un po 'e in quella modalità gli allarmi non verranno forniti. Tuttavia, esiste un modo per le app di dire esplicitamente "Ho bisogno che questa sveglia si attivi in ​​questo momento indipendentemente dall'utilizzo della batteria"; i nuovi metodi AlarmManager chiamati setAndAllowWhileIdle()e setExactAndAllowWhileIdle().

Dalla tua descrizione sembra che questa potrebbe non essere la causa particolare dei tuoi problemi su alcuni dispositivi OEM, ma questo è qualcosa di cui tutti gli sviluppatori che utilizzano Alarm Manager dovrebbero essere a conoscenza.

Infine, molti utilizzi di Alarm Manager vengono affrontati meglio utilizzando i meccanismi di Job Scheduler. Per compatibilità con le versioni precedenti, il "GCM Network Manager" di Play Services è in realtà molto simile al Job Scheduler in termini di funzionalità - utilizza il Job Scheduler internamente sulle versioni più recenti di Android - e non riguarda necessariamente il networking, nonostante il nome della classe.


I dispositivi Samsung con Smart Manager eseguono Lollipop. Sto già utilizzando setExactAndAllowWhileIdle per i dispositivi Marshmallow. Darò uno sguardo a JobScheduler e GCM. Ad ogni modo, non so se il problema è che l'allarme non si attiva o se quel dispositivo non si attiva quando l'allarme suona.
Sergio Viudes

0

Non penso che uccidere l'app impedirà al gestore degli allarmi di riattivare l'app.

È solo quando si "forza l'arresto" o si disabilita l'app non si riceve la chiamata dal gestore degli allarmi.

La causa principale potrebbe essere qualcos'altro.

Anche su M ... setExactAndAllowWhileIdle fa throttling ... cioè se pianifichi un allarme ogni 2 minuti, non verrà attivato. .. Deve esserci una finestra di 15 minuti. .


1
Grazie per la tua risposta. Ma, se no, perché l'app funziona perfettamente quando "ottimizzazione batteria" è disabilitata in Smart Manager?
Sergio Viudes

stai eseguendo l'app su un dispositivo rooted..se sì, l'app manager può disabilitare anche l'app ..
rupesh jain

No, non lo sto eseguendo su un dispositivo rooted.
Sergio Viudes

@rupeshjain "cioè se pianifichi un allarme ogni 2 minuti, non verrà attivato ... Ci deve essere una finestra di 15 minuti." questo non è completamente vero, è un vero problema se fosse vero. Puoi leggere esattamente quale sia il limite di tempo per la pianificazione all'interno di Documenti Android per il metodo setExactAndAllowWhileIdle. Esistono limitazioni sulla frequenza con cui questi allarmi si attivano per una particolare applicazione. Durante il normale funzionamento del sistema, non invierà questi allarmi più di circa ogni minuto quando in modalità di inattività a basso consumo questa durata può essere significativamente più lunga di 15 minuti.
eyadMhanna

0

Per Xiaomi potrebbe essere necessario abilitare l'AutoStart per la tua app. Sto cercando di fare un elenco di modifiche Android (di solito dal produttore del telefono) che possono influenzare un processo in background. Se hai qualcosa di nuovo, aggiungi una risposta qui Elenco di task killer Android


0

Dobbiamo abilitare la nostra app nel gestore di avvio automatico in app manager, alcuni telefoni come vivo v5,

In vivo v5, possiamo trovare questo menu in iManager -> App Manager -> Auto Start Manager. Abilita la nostra app qui.

Quindi il tuo allarme / gestore degli allarmi attiverà l'allarme se l'app viene interrotta o chiusa.


0

Stavo cercando una risposta e dopo diverse ore ho trovato questa:

https://stackoverflow.com/a/35220476/3174791

Nel curriculum c'è un modo per sapere se la tua app è stata uccisa da `` App protette '' e questo funziona solo sui dispositivi Huawei. fammi sapere se esiste una soluzione per altri dispositivi (Samsung, Sony, Xiaomi, ecc.).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.