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.