studio siempre servicios servicio segundo saber plano mantener example esta editar crear corriendo como aplicacion androidmanifest activo abierta android android-service

android - siempre - Continuar con el servicio incluso si la aplicación se borra de la aplicación reciente



servicio siempre activo android studio (6)

Estoy teniendo un pequeño problema

En mi aplicación, se inicia un Servicio después de que el usuario haya iniciado sesión correctamente. Anteriormente, el servicio debía detenerse si se cancelaba la aplicación. (por ejemplo, eliminado de la lista de aplicaciones recientes al deslizar). Así que usamos android:stopWithTask="true" . Ahora necesitamos que el Servicio se ejecute tal como está, incluso si la Tarea que lo inició, se elimina de la lista de Aplicaciones recientes. Así que cambié el Servicio para incluir android:stopWithTask="false" . Pero eso no parece funcionar.

Código relacionado:

Aquí está la parte manifiesta relacionada con el Servicio:

<service android:enabled="true" android:name=".MyService" android:exported="false" android:stopWithTask="false" />

En MyService.java:

public class MyService extends AbstractService { @Override public void onStartService() { Intent intent = new Intent(this, MyActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); Notification notification = new Notification(R.drawable.ic_launcher, "My network services", System.currentTimeMillis()); notification.setLatestEventInfo(this, "AppName", "Message", pendingIntent); startForeground(MY_NOTIFICATION_ID, notification); } @Override public void onTaskRemoved(Intent rootIntent) { Toast.makeText(getApplicationContext(), "onTaskRemoved called", Toast.LENGTH_LONG).show(); System.out.println("onTaskRemoved called"); super.onTaskRemoved(rootIntent); } }

AbstractService.java es una clase personalizada que extiende Sevrice :

public abstract class AbstractService extends Service { protected final String TAG = this.getClass().getName(); @Override public void onCreate() { super.onCreate(); onStartService(); Log.i(TAG, "onCreate(): Service Started."); } @Override public final int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStarCommand(): Received id " + startId + ": " + intent); return START_STICKY; // run until explicitly stopped. } @Override public final IBinder onBind(Intent intent) { return m_messenger.getBinder(); } @Override public void onDestroy() { super.onDestroy(); onStopService(); Log.i(TAG, "Service Stopped."); } public abstract void onStartService(); public abstract void onStopService(); public abstract void onReceiveMessage(Message msg); @Override public void onTaskRemoved(Intent rootIntent) { Toast.makeText(getApplicationContext(), "AS onTaskRemoved called", Toast.LENGTH_LONG).show(); super.onTaskRemoved(rootIntent); } }

Ahora, si inicio sesión en la aplicación, se inicia MyService. Después de eso presiono el botón de Inicio, por lo que la aplicación se mueve al fondo. Ahora elimino la aplicación de la lista de aplicaciones recientes. En ese momento, debería ver el mensaje Toast y la consola, según la descripción de este método:

public void onTaskRemoved (Intento rootIntent)

Agregado en API nivel 14

Esto se llama si el servicio se está ejecutando actualmente y el usuario ha eliminado una tarea que proviene de la aplicación del servicio. Si ha configurado ServiceInfo.FLAG_STOP_WITH_TASK, no recibirá esta devolución de llamada; en cambio, el servicio simplemente se detendrá.

Parámetros rootIntent Intento raíz original que se utilizó para iniciar la tarea que se está eliminando.

Pero no estoy viendo nada de eso. El servicio regresa START_STICKY en onStartCommand , por lo que creo que onTaskRemoved debería onTaskRemoved junto con el indicador android:stopWithTask="false" .

¿Me estoy perdiendo algo?

Avíseme en caso de que necesite agregar algún código que podría ser importante para descubrir qué está mal.

PD: Probé esto en 4.2.2 hasta ahora.

PD: acabo de probar el mismo código en 4.1.2, en el que el Servicio sigue ejecutándose, y también recibo el mensaje "onTaskRemoved llamado" en el registro.

¿Qué debo hacer para que esto funcione en todas las versiones?


En su servicio, agregue el siguiente código. Me funciona bien en 4.4.2

Aquí hay una solución que encontré y funciona bien para reiniciar un servicio si su proceso se cierra al cerrar la aplicación.

@Override public void onTaskRemoved(Intent rootIntent){ Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass()); PendingIntent restartServicePendingIntent = PendingIntent.getService( getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT); AlarmManager alarmService = (AlarmManager) getSystemService(Context.ALARM_SERVICE); alarmService.set(ELAPSED_REALTIME, elapsedRealtime() + 1000, restartServicePendingIntent); super.onTaskRemoved(rootIntent); }


Escriba las 5 líneas que agregué en oncreate() de la clase de servicio

Me gusta esto:

public class AlarmService extends Service { @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); Intent iHeartBeatService = new Intent(AlarmService.this, AlarmService.class); PendingIntent piHeartBeatService = PendingIntent.getService(this, 0, iHeartBeatService, PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(piHeartBeatService); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000, piHeartBeatService); } }

o

prueba este

public class MyService extends Service{ @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); System.out.println("service created"); } @SuppressLint("NewApi") @Override public void onTaskRemoved(Intent rootIntent) { // TODO Auto-generated method stub System.out.println("onTaskRemoved"); super.onTaskRemoved(rootIntent); } @Override @Deprecated public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub super.onStart(intent, startId); System.out.println("Service started"); new Handler().postDelayed(new Runnable() { @Override public void run() { // TODO Auto-generated method stub System.out.println("Service is running"); } }, 5000); } }


Parece que quitar una aplicación de las ''tareas recientes'' mata todo lo adjunto.

Tal vez debería echar un vistazo allí para encontrar una manera de relanzar su servicio si se detiene: https://.com/a/22464640/4232337


Si está bien poner una notificación mientras el servicio se está ejecutando, puede usar startForegroundService y startForeground para lograrlo.

Hay tres trucos importantes:

  1. Llame a startForegroundService que crea un servicio de larga ejecución no limitado al contexto enlazado y haga una promesa de llamar a startForeground más tarde.
  2. Regrese START_STICKY en onStartComand
  3. Llame a startForeground con una notificación como se prometió en (1).

Por ejemplo, si desea ejecutar un TimerService, en su TimerActivity hará lo siguiente:

private var timerService: TimerService? = null private val timerServiceConnection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { val binder = service as TimerService.Binder timerService = binder.getService() } override fun onServiceDisconnected(arg0: ComponentName) { } } override fun onCreate(savedInstanceState: Bundle?) { ... startButton.setOnClickListener { timerService?.startTimer(60L, 0L) } } override fun onStart() { super.onStart() Intent(this, TimerService::class.java).also { ContextCompat.startForegroundService(this, it) // that''s the first trick bindService(it, timerServiceConnection, Context.BIND_AUTO_CREATE) } } override fun onStop() { super.onStop() unbindService(timerServiceConnection) timerService?.updateNotification(secondsRemaining) }

Su TimerService será algo así:

class TimerService : Service() { private val binder = Binder() private var serviceLooper: Looper? = null private var serviceHandler: ServiceHandler? = null private var timer: CountDownTimer? = null private val notificationUtil by lazy { NotificationUtil(this) } override fun onCreate() { HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply { start() serviceLooper = looper serviceHandler = ServiceHandler(looper) } } override fun onBind(intent: Intent?): IBinder? = binder override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { val timerRemaining = intent?.getLongExtra(EXTRA_REMAINING, 0) ?: 0L if (timerRemaining != 0L) { serviceHandler?.obtainMessage()?.also { msg -> msg.arg1 = startId msg.data.putLong(EXTRA_REMAINING, timerRemaining) serviceHandler?.sendMessage(msg) } } return START_STICKY // that''s the second trick } override fun onDestroy() { super.onDestroy() timer?.cancel() } fun startTimer(secondsRemaining: Long, id: Long) { updateNotification(secondsRemaining) Intent(this, TimerService::class.java).apply { putExtra(EXTRA_REMAINING, secondsRemaining) }.also { onStartCommand(it, 0, id.toInt()) } } fun stopTimer() { timer?.cancel() } fun updateNotification(secondsRemaining: Long){ val notification = NotificationCompat.Builder(this, NotificationUtil.CHANNEL_ID_TIMER) .setSmallIcon(R.drawable.ic_timer) .setAutoCancel(true) .setDefaults(0) .setContentTitle(secondsRemaining.formatSeconds()) .setContentText("Timer") .setContentIntent(notificationUtil.getPendingIntentWithStack(this, TimerActivity::class.java)) .setOngoing(true) .build() startForeground(NotificationUtil.NOTIFICATION_ID, notification) // that''s the last trick } private fun sendMessage(remaining: Long) { Intent(TimerService::class.java.simpleName).apply { putExtra(EXTRA_REMAINING, remaining) }.also { LocalBroadcastManager.getInstance(this).sendBroadcast(it) } } private inner class ServiceHandler(looper: Looper) : Handler(looper) { override fun handleMessage(msg: Message) { val secondsRemaining = msg.data.getLong(EXTRA_REMAINING) notificationUtil.showTimerStarted(secondsRemaining) timer = object : CountDownTimer(secondsRemaining * 1000, 1000) { override fun onTick(millisUntilFinished: Long) { Log.i(this::class.java.simpleName, "tick ${(millisUntilFinished / 1000L).formatSeconds()}") updateNotification(millisUntilFinished / 1000) sendMessage(millisUntilFinished / 1000) } override fun onFinish() { Log.i(this::class.java.simpleName, "finish") notificationUtil.showTimerEnded() sendMessage(0) stopSelf() } }.start() } } inner class Binder : android.os.Binder() { // Return this instance of LocalService so clients can call public methods fun getService(): TimerService = this@TimerService } companion object { const val EXTRA_REMAINING = "EXTRA_REMAINING" const val NOTIFICATION_ID = 1 // cannot be 0 fun Long.formatSeconds(): String { val s = this % 60 val m = this / 60 % 60 val h = this / (60 * 60) % 24 return if (h > 0) String.format("%d:%02d:%02d", h, m, s) else String.format("%02d:%02d", m, s) } } }


Si se une a su servicio desde una subclase de clase de Aplicación y mantiene su conexión de IBinder, el servicio permanecerá activo incluso después de que la aplicación se elimine de las aplicaciones recientes.


Simplemente siga estos escenarios, su servicio y procesos (los hilos se ejecutan dentro de su servicio) permanecerán continuos.

  1. Cree el servicio y use START_STICKY como valor de retorno en el método onStartCommand como se muestra a continuación:

    @Override public int onStartCommand(final Intent intent, final int flags, final int startId) { //your code return START_STICKY; }

  2. El código anterior reiniciará el servicio si se destruye y siempre se mantendrá en ejecución, pero el proceso (subprocesos) ejecutado desde el servicio dejará de funcionar si su aplicación se elimina de las aplicaciones recientes. Para garantizar que sus procesos (subprocesos) permanezcan siempre en condiciones de ejecución, debe anular el método onTaskRemoved () y agregar código para reiniciar las tareas como se muestra a continuación.

    @Override public void onTaskRemoved(Intent rootIntent){ Intent restartServiceTask = new Intent(getApplicationContext(),this.getClass()); restartServiceTask.setPackage(getPackageName()); PendingIntent restartPendingIntent =PendingIntent.getService(getApplicationContext(), 1,restartServiceTask, PendingIntent.FLAG_ONE_SHOT); AlarmManager myAlarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE); myAlarmService.set( AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000, restartPendingIntent); super.onTaskRemoved(rootIntent); }

  3. Iniciar servicio como a continuación

startService (nueva intención (esto, YourService.class));