Iniciar IntentService Android com AlarmManager e BroadcastReceiver

postado em: Android | 0

Olá pessoal,

Hoje vou mostrar um exemplo de aplicativo que inicia um IntentService no Android usando AlarmManager e este serviço envia mensagens para a tela do app.

Estou disponibilizando este exemplo porque demorou um pouco pra chegarmos neste modelo, e não haviam muitos exemplos que atendessem a nossa necessidade.

Temos um projeto em um dos nossos clientes que roda o serviço em background pois necessita realizar a sincronização dos dados de tempos em tempos. Essa sincronização é necessária pois o aplicativo roda off-line. Uma das boas práticas para economia de energia do aparelho e adotada fortemente a partir do Android 8 é não deixar serviços rodando eternamente, por isso precisávamos de uma solução que iniciasse a sincronização automaticamente, pois isso não poderia ficar a cargo do usuário. Na época, a solução que encontramos e nos atendeu muito bem foi o AlarmManager, pois ele roda no tempo programado e inicia o serviço.

Para iniciar o AlarmManager, setar os seguintes dados:

// Instancia o broadcast
Intent intent = new Intent(mContext, MyAlarmManagerReceiver.class);

// Cria um PendingIntent para ser disparado quando o alarme iniciar. REQUEST_CODE é o identificador da sua chamada.
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, MyAlarmManagerReceiver.REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);

// Intancia o AlarmManager
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);

// Pega o tempo atual para iniciar o servico (pode setar um tempo no futuro)
long firstStartMillis = System.currentTimeMillis();

// Intervalo em milissegundos
// Caso queira, pode usar um dos tempos disponibilizados pela lib.
// Ex: AlarmManager.INTERVAL_FIFTEEN_MINUTES, AlarmManager.INTERVAL_HALF_HOUR etc
long intervalMillis = (1 * 60 * 1000); // 1 minuto

// Seta a data de inicio do alarm
// First parameter is the type: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC_WAKEUP
// Interval can be INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, firstStartMillis, intervalMillis, pendingIntent);

Feito isso, seu alarme está registrado no sistema e será chamado assim que o sistema rodar a coleta de alarmes e a data de início for menor ou igual a data atual.

Quando o sistema disparar o seu alarmManager, você deve interceptar essa ação utilizando uma classe que estende de BroadcastReceiver. Nessa classe, deve conter o seguinte código dentro do método onReceive:

// Cria o Intent com a classe do serviço
Intent iService = new Intent(pContext, MyIntentService.class);

// Valida a versao do Android. A partir do 8, usar startForegroundService
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    ContextCompat.startForegroundService(pContext, iService);

} else {
    pContext.startService(iService);
}

Ao cair neste ponto, seu serviço será iniciado.

A partir do Android 8, no onCreate do serviço, é necessário criar uma notificação com startForeground em até 5 segundos, caso contrário o serviço será interrompido.

// Necessário somente a partir da versão 8 do Android
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    // Cria notificação em foreground. Se não chamar o startForeground em até 5 segundos, será gerado um erro em tempo de execução
    this.showProgressNotification(message, false, true);
}

Uma dica importante: utilize sempre um número maior que 0 no ID da sua notificação. Quando estava testando o app, estava com erro para iniciar no Android 8 por que eu estava usando 0.

// Pega a notification do builder
Notification notification = mBuilder.build();

// Exibe a notificação. Utilizar ID maior que 0
startForeground(3, notification);

Então no método onHandleIntent você vai criar a sua lógica e atualizar o Progress Notification.

Caso precise atualizar a tela do seu aplicativo com alguma informação do serviço, na tela que irá receber essa informação você vai registrar um BroadcastReceiver com uma action de identificação.

// Instancia o receiver
myReceiver = new ReceiverServiceProgress();

// Cria o filter
IntentFilter filter = new IntentFilter();
filter.addAction(MyIntentService.ACTION_NOTIFY_SYNC_STATUS);

// Registra o receiver
registerReceiver(myReceiver, filter);

Lembrando sempre de registrar o receiver ao abrir a tela e remover ao fechá-la.

Aí no serviço basta enviar a mensagem através do método sendBroadcast passando a action para identificação:

// Seta o intent
Intent intent = new Intent(ACTION_NOTIFY_SYNC_STATUS);

// Passa os parâmetros no intent
intent.putExtra(EXTRA_STATUS_PROGRESS, progress);
intent.putExtra(EXTRA_IS_FINISHED, isFinished);

// Notifica o broadcast
sendBroadcast(intent);

Pronto, seu serviço com start automático, com barra de progresso e comunicação com a tela do seu app está pronto.

Segue o link do projeto no Github:

https://github.com/altieresbianchi/AlarmManagerStartService

É isto, espero ter ajudado!

Comentários são bem-vindos.

Seguir Altieres Bianchi:

Analista Desenvolvedor Mobile e Web, formado pela Universidade Tuiuti do Paraná e pós-graduado pela UTFPR.