AlarmManager não funciona em vários dispositivos


85

Meu aplicativo usa AlarmManager e está funcionando há 4 anos. Mas percebi que começou a falhar em alguns dispositivos.

Tenho quase certeza de que o código está correto (estou usando WakefulBroadcastReceiver e setExactAndAllowWhileIdle para dispositivos com Doze) porque está funcionando perfeitamente em dispositivos Nexus, mas falha em dispositivos de alguns fabricantes (Huawei, Xiaomi ...).

Dispositivos Huawei, por exemplo, têm um tipo de gerenciador de bateria que mata aplicativos e, quando um aplicativo é encerrado, os alarmes programados são cancelados. Portanto, definir um aplicativo como "protegido" no gerenciador de bateria da Huawei resolve o problema.

Mas recentemente percebi que ele não está funcionando com mais dispositivos: Xiaomi, Samsung (talvez seja relacionado ao novo "Smart Manager"?) ... Parece que esse comportamento está se tornando um padrão: matar aplicativos em segundo plano.

Alguém sabe algo sobre isso? Há alguma maneira de garantir que o alarme seja disparado?

EDITAR: Este problema é causado por "economizadores de bateria" adicionados por diferentes fabricantes. Mais informações aqui: https://dontkillmyapp.com/


8
Os fabricantes culpam os aplicativos pelo consumo de energia e continuam a comercializar os Octa-cores, que consomem mais bateria em comparação com a CPU com menos núcleos. Eles acham que simplesmente adicionar um núcleo aceleraria seus telefones?
FrozenFire de

1
@AviLevinshtein Talvez eu tenha entendido mal sua pergunta. Estou criando os alarmes em minha atividade. Então, quando o alarme dispara, um broadcast receiver é executado e, finalmente, um WakefulIntentService (classe de @commonsware) é executado.
Sergio Viudes

2
@JFValdes Ainda estou procurando uma solução. AlarmManager está funcionando perfeitamente em dispositivos com Vanilla Android. O problema é que os fabricantes estão tentando "aprimorar" os recursos do Android e quebraram o AlarmManager ... Os fabricantes não devem implementar seus próprios "economizadores de bateria", se usarem o modo Soneca padrão, o AlarmManager funcionará perfeitamente ... Ainda procurando por uma solução ...
Sergio Viudes

1
Existe alguma solução ainda? Como outros aplicativos, como lembretes ou algo assim, fazem isso? Deve haver outra opção além de setAlarm, que é para alarmes, não para lembretes
kv1dr

1
@SergioViudes Também estou enfrentando o mesmo problema com os dispositivos Xiomi para rastreamento. e se eu impedir meu aplicativo da restrição de economia de bateria, então ele está funcionando corretamente em 3 de 4 dispositivos, fazendo as seguintes configurações - -> Vá para a bateria -> Energia -> Economia de bateria do aplicativo -> seu aplicativo Agora selecione Sem restrições (para configurações de fundo) e depois opção Permitir para localização de fundo
Imran Khan Saifi

Respostas:


17

Estou tentando resolver isso há várias semanas. Não encontrei nada. Huawei acaba com todos os alarmes depois de algum tempo. Se eu colocar o aplicativo no aplicativo protegido na economia de bateria, isso não ajudará. Mas se eu alterar o nome do pacote do meu aplicativo para conter palavras como alarme, relógio ou calendário, ele funciona absolutamente normal como em qualquer outro dispositivo. Não entendo como o Google pode dar certificação para essa porcaria. Eu acho que o OEM não deve modificar a plataforma central dessa forma. Eu entendo que eles têm o próprio protetor de bateria que mata o aplicativo depois de algum tempo, quando o usuário não o usa. Mas isso matando alarmes também de aplicativos protegidos.

Também setAlarmClock () para alarmes de temporização exata ajuda. Mas não é possível usar isso para pensar como atualização de widget.

Atualização: a proteção por palavras-chave do nome do pacote já não está funcionando nos dispositivos Huawei atuais, era verdade em 2017.


Mesmo que eu, eu também tento, mas nada para resolver esse problema em alguma marca Xiaomi, Oppo, Huawei. Às vezes, eles eliminam o processo de fundo e o alarme para economizar bateria.
Andi Susilo

1
Eu tenho o telefone huawei, mudar o nome do pacote para alarme / calendário não faz nada. Única maneira de contornar isso, adicione seu aplicativo na lista de aplicativos protegidos do gerenciador de telefones
Ashish Pardhiye

9

O problema é o Smart Manager. A Samsung possui um gerenciador de bateria que às vezes desativa a execução de certos aplicativos em segundo plano. Ele tentou "retomar" ao voltar ao aplicativo, mas desabilitou completamente o aplicativo ou pode retomar a cada 5 minutos ou mais (dependendo de como a Samsung o possui).

Isso funcionaria em versões de estoque do Android, pois não há Gerenciador Samsung. Você também pode instalar a versão personalizada do Android, que possui alguns recursos para habilitar o SM (dependendo da rom).


Estou ficando louco porque não tenho nenhum dispositivo Samsung para testá-lo. Só sei o que os usuários do meu aplicativo estão me dizendo. Você sabe se o problema é que o AlarmManager não está funcionando porque o aplicativo foi encerrado? Ou o problema é que o dispositivo não pode acordar quando o alarme dispara por causa desse gerenciador?
Sergio Viudes de

@SergioViudes Recentemente, muitas empresas têm implementado o seu próprio. Tal como a LG tem um que funciona de forma semelhante ao Samsung, talvez o seu telefone tenha um? O problema não é o alarme, o aplicativo de alarme é colocado em um estado em que fica completamente inativo. O Smart Manager pensa que é apenas um aplicativo aleatório de que você não precisa. Percebi que alguns aplicativos podem passar por isso, talvez alguns aplicativos sejam aceitos pelo gerenciador inteligente.
SA de

1
@SergioViudes Tenho um Samsung para testar e posso dizer que não há muito que você possa tirar dele. Quando o gerenciador inteligente otimiza seu aplicativo, não há erro nem nada, ele simplesmente morre, semelhante a uma parada forçada. Ainda está na lista de aplicativos recentes
Tim

Obrigado Tim. Seria ótimo resolver esse problema sem ter que excluir aplicativos do Gerenciador "Inteligente".
Sergio Viudes

dispositivos como xiaomi (miui), vivo e htc definem um monte de permissões como falsas por padrão, a menos que seja um aplicativo na lista de aplicativos "confiáveis" que eles parecem determinar (whatsapp, truecaller, etc. são confiáveis ​​por padrão ) Isso está se tornando um pesadelo para os programadores
desidigitalnomad

4

A maioria dos dispositivos Android modernos vem com um aplicativo ou mecanismo, que tenta automagicamente descobrir como economizar bateria e, como resultado, pode matar alguns aplicativos de terceiros. Isso pode resultar na remoção de tarefas e trabalhos agendados (por exemplo, alarmes que não disparam, notificação push que não funciona, etc.). Em muitos casos, isso acontece completamente independente dos mecanismos de economia de bateria do Android, no meu caso não consegui otimizar mais a bateria quando detectei o modelo de alguns dispositivos, redirecionei o usuário para o gerenciador de inicialização para colocar meu aplicativo na lista de permissões

Você encontrou neste link para cada modelo a intenção que você deve invocar https://android-arsenal.com/details/1/6771


2

Use AlarmManager para dispositivos <5.0 e JobScheduler para dispositivos 5.0+. Não posso dizer com certeza se o JobScheduler não será afetado pelas travessuras do fabricante, mas parece muito menos provável para mim, visto que o Android está tentando mover as pessoas do AlarmManager para o JobScheduler.

EDIT: O Google lançou uma solução primária para este problema chamada WorkManager . Ele abstrai várias estruturas de agendamento e usa a mais adequada para o dispositivo.


2
Infelizmente, ao contrário da classe AlarmManager, o tempo não é exato ao usar JobScheduler. No meu aplicativo, o tempo deve ser exato :(
Sergio Viudes

Eu tentei e alguns otimizadores (pelo menos samsung) eliminam todas as tarefas pendentes no JobScheduler quando a tela apaga. Então também está quebrado. Isso acontece no 5.0. Depois de atualizar para 6.0 funciona bem, acho que eles consertaram isso. Ainda não consegui testar com outros fabricantes.
Sloy

Para obter o tempo exato, você não pode usar um serviço em segundo plano ou serviço programado. Você pode tentar um serviço de primeiro plano, mas isso criará uma notificação persistente para o usuário (provavelmente indesejável) e alguns telefones têm eliminadores de tarefas embutidos que destruirão automaticamente o serviço de primeiro plano. WorkManager é a melhor solução, mas infelizmente não fornecerá os tempos exatos.
Tom

1

Eu também tenho um aplicativo que define alarmes. A solução é usar AlarmManager.setAlarmClock () em api> = 21. Isso não é afetado por doze afaik e tem o bônus adicional de colocar um ícone de despertador na bandeja do sistema.


Obrigado pela sua resposta. Existe alguma maneira de remover o ícone do despertador?
Sergio Viudes

Infelizmente, setAlarmClock não funciona às vezes. Eu testei no dispositivo Oreo com pouca memória.
Boris Salimov

1

Pode ser tarde, mas espero que ajude alguém.

Eu estava preso no mesmo problema por tanto tempo. Mas agora eu sei como resolver esse problema. Isso é para qualquer pessoa que possa ter o mesmo problema. As pessoas continuam dizendo que você tem que habilitar o AutoStart, mas eu consegui sem usar o auto start.

Primeiro de tudo, WakeFullBroadcastaReceiver agora está obsoleto e você deve usar BroadcastReceiver. Em segundo lugar, você deve usar o ForegroudService em vez do BackgroundService.

Vou te dar o exemplo a seguir:

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+
}
}

inicie o serviço de primeiro plano em 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 o setAlarms assim:

 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);
    }

Em seguida, você deve declarar o destinatário e o foregroundservice no manifesto.

       <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>

Espero que isso ajude alguém.


mas ninguém está dando um voto positivo? @ keivan.k
gumuruh

0

a maioria dos novos telefones hoje em dia vem com algum tipo de gerenciador de bateria / economia de energia que faz a mesma coisa que você descreveu. sem contar duboosters e mestres limpos.

Acho que você precisa colocar um aviso de isenção de responsabilidade ou faq na sua lista de aplicativos / loja do jogo informando que este aplicativo precisa ser colocado em exceção do seu aplicativo de gerenciamento de bateria para funcionar corretamente.


Deve haver outra maneira de fazer isso ... Os usuários não lerão o aviso de isenção. Não consigo pensar que os telefones Samsung não permitem que os aplicativos usem o AlarmManager ...
Sergio Viudes

Os alarmes não dispararão "a tempo", mas irão eventualmente
Gavriel

Esta é (infelizmente) a resposta mais útil, eu diria. Eu gostaria que houvesse uma solução melhor, mas os fabricantes de hardware estão danificando o Android que funciona perfeitamente.
caw

0

parei de usar AlarmManager há um tempo ... uma alternativa melhor e mais estável

  1. criar um serviço
  2. registrar um BroadcastReceiver para BOOT_COMPLETED
  3. dispare seu serviço do receptor
  4. inicie um novo Handler dentro do seu serviço que faça um loop a cada X minutos ( Android - executando um método periodicamente usando a chamada postDelayed () )
  5. verifique se chegou a hora de executar a tarefa: agora - tempo de execução> 0 ( como encontrar a duração da diferença entre duas datas em java? )
  6. se assim for .. execute a tarefa e pare o manipulador

sim .. é uma dor .. mas o trabalho é feito NÃO IMPORTA O QUE


3
Obrigado pela sua sugestão, mas gostaria de evitar essa abordagem, porque o uso de AlarmManager não consumirá RAM ou qualquer recurso. E, se seu aplicativo for encerrado, o serviço parará, certo?
Sergio Viudes

Eu não disse que essa abordagem é BOOLETPROOF, mas pelo menos consiste em diferentes versões da API :)
ymz

1
Para funcionar de forma confiável, essa solução provavelmente também precisaria usar wake locks, o que consumiria grandes quantidades de bateria.
Paweł Nadolski

Eu acho que você está certo sobre este .. a única pergunta é: o que seria pior - código não confiável ou desempenho ruim? de qualquer forma, eu pessoalmente acho que existem maneiras alternativas de bloqueio que podem ser adequadas em alguns casos (por exemplo: stackoverflow.com/questions/5346694/… )
ymz

mas, o mecanismo principal - receptor de Broadcas - não é chamado \
Noor Hossain

0

Você está ouvindo BOOT_COMPLETED? Você precisa definir alarmes novamente quando um dispositivo é reiniciado.


Sim. Como eu disse, os alarmes estavam funcionando desde 2012, até agora. Quando o dispositivo é reiniciado, eu reprogramaço os alarmes no receptor de transmissão BOOT_COMPLETED.
Sergio Viudes de

1
Exigir uma reinicialização para seu aplicativo funcionar novamente não é nem metade uma solução
Tim

1
@TimCastelijns não é isso que estou dizendo. SE o dispositivo for reinicializado, todos os alarmes configurados com o gerenciador de alarmes devem ser configurados novamente.
Tyler Pfaff

@TylerPfaff sim, mas a reinicialização do dispositivo não está relacionada ao problema nesta questão
Tim

0

Qual versão do Android esses dispositivos estão executando?

A partir da API 23, o próprio sistema operacional entrará em um modo ocioso de baixo consumo de energia quando não for usado por um tempo e, nesse modo, os alarmes não serão emitidos. No entanto, há uma maneira de os aplicativos dizerem explicitamente "Preciso que este alarme toque neste momento, independentemente do uso da bateria"; os novos métodos AlarmManager chamados setAndAllowWhileIdle()esetExactAndAllowWhileIdle() .

Pela sua descrição, parece que essa pode não ser a causa específica de seus problemas em determinados dispositivos OEMs, mas isso é algo que todos os desenvolvedores que usam o Alarm Manager devem estar cientes.

Finalmente, muitos usos do Alarm Manager são melhor tratados usando os mecanismos do Job Scheduler. Para compatibilidade com versões anteriores, o Play Services "GCM Network Manager" é, na verdade, muito próximo do Job Scheduler em funcionalidade - ele usa o Job Scheduler internamente em versões mais recentes do Android - e não é necessariamente sobre rede, apesar do nome da classe.


Os dispositivos Samsung com Smart Manager estão executando o Lollipop. Já estou usando setExactAndAllowWhileIdle para dispositivos Marshmallow. Vou dar uma olhada em JobScheduler e GCM. Enfim, não sei se o problema é que o alarme não dispara, ou se aquele aparelho não desperta quando o alarme dispara.
Sergio Viudes

0

Não acho que matar o aplicativo irá impedir que o gerenciador de alarme desperte seu aplicativo.

Somente quando você "forçar a parada" ou desabilitar o aplicativo, você não receberá retornos de chamada do gerenciador de alarme.

A causa raiz pode ser outra coisa.

Também no M ... setExactAndAllowWhileIdle faz o throttling ... ou seja, se você programar um alarme a cada 2 minutos, ele não será acionado. .. Deve haver uma janela de 15 minutos. .


1
Obrigado pela sua resposta. Mas, se não, por que o aplicativo está funcionando perfeitamente quando a "otimização da bateria" está desabilitada no Smart Manager?
Sergio Viudes

você está executando o aplicativo em um dispositivo com acesso root ... se sim, o gerenciador de aplicativos também pode desativar o aplicativo ..
rupesh jain

Não, não estou executando em um dispositivo com acesso root.
Sergio Viudes

@rupeshjain "isto é, se você programar um alarme a cada 2 minutos, ele não será acionado. ... Deve haver uma janela de 15 minutos." isso não é totalmente verdade, é um problema real se for verdade. Você pode ler exatamente qual é o limite de tempo para agendamento dentro do Android Docs para o método setExactAndAllowWhileIdle. Existem restrições sobre a frequência com que esses alarmes disparam para uma aplicação específica. Em operação normal do sistema, ele não disparará esses alarmes mais do que a cada minuto, quando em modos ociosos de baixa energia, essa duração pode ser significativamente maior de 15 minutos.
eyadMhanna

0

Para Xiaomi, pode ser necessário habilitar o AutoStart para seu aplicativo. Estou tentando fazer uma lista de modificações do Android (geralmente do fabricante do telefone) que podem afetar um processo em segundo plano. Se você tem algo novo, adicione uma resposta aqui Lista de assassinos de tarefas Android


0

Precisamos habilitar nosso aplicativo no gerenciador de inicialização automática no gerenciador de aplicativos, alguns aparelhos como vivo v5,

In vivo v5, podemos encontrar este menu em iManager -> App Manager -> Auto Start Manager. Habilite nosso aplicativo aqui.

Em seguida, seu alarme / gerenciador de alarmes disparará o alarme se o aplicativo for encerrado ou fechado.


0

Eu estava procurando uma resposta e depois de várias horas encontrei o seguinte:

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

Em resumo, é uma forma de saber se seu aplicativo foi interrompido por 'Aplicativos protegidos' e isso só funciona em dispositivos Huawei. deixe-me saber se existe alguma solução para outros dispositivos (Samsung, Sony, Xiaomi, etc).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.