tipos studio siempre servicios servicio segundo programacion plano notificaciones mantener implementar ejemplo app aplicacion abierta android service background intentservice

studio - servicio de notificaciones android



Android: mantener el servicio en ejecuciĆ³n cuando se elimina la aplicaciĆ³n (6)

En su servicio, agregue el siguiente código.

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

Quiero mantener un IntentService ejecutándose en segundo plano, incluso cuando la aplicación está IntentService . Y por "muerto" me refiero a presionar el botón de inicio durante mucho tiempo -> ver todas las aplicaciones en ejecución -> deslizar mi aplicación a un lado -> aplicación eliminada O presionar el botón Atrás durante mucho tiempo -> aplicación eliminada

Mi código es el siguiente. En mi MainActivity:

Intent intent = new Intent(this, MyService.class); this.startService(intent);

En mi MyService:

public class MyService extends IntentService { @Override protected void onHandleIntent(Intent intent) { System.out.println("MyService started"); run(); } private void run() { while (true){ System.out.println("MyService still running"); doSomething(); waitSomeTime(); } } }

Veo que el servicio se está ejecutando cuando la aplicación está abierta . Todavía se está ejecutando cuando minimizo la aplicación a través del botón de inicio. Todavía se está ejecutando cuando cierro la aplicación con el botón de retroceso. Pero se detendrá si lo mato como se mencionó anteriormente. ¿Cómo puedo solucionar esto?


La razón de esto es que está intentando usar un IntentService. Aquí está la línea de los documentos API

El IntentService hace lo siguiente:

Detiene el servicio después de que se hayan manejado todas las solicitudes de inicio, por lo que nunca tendrá que llamar a stopSelf ().

Por lo tanto, si desea que su servicio se ejecute indefinidamente, le sugiero que amplíe la clase de Servicio en su lugar. Sin embargo, esto no garantiza que su servicio se ejecute indefinidamente. Su servicio todavía tendrá la posibilidad de ser destruido por el kernel en un estado de poca memoria si es de baja prioridad. Así que tiene dos opciones:
1) Manténgalo funcionando en primer plano llamando al método startForeground() .
2) Reinicie el servicio si muere. Aquí hay una parte del ejemplo de los documentos donde se habla de reiniciar el servicio después de que se cancele.

public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we''re stopping when we finish the job Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; mServiceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_STICKY; }


Puede usar android:stopWithTask="false" en el manifiesto como se android:stopWithTask="false" continuación. Esto significa que incluso si el usuario mata la aplicación al eliminarlo de la lista de tareas, su servicio no se detendrá.

<service android:name=".service.StickyService" android:stopWithTask="false"/>


Si su aplicación inicia su Servicio, en realidad su servicio se está ejecutando en el proceso principal. por lo tanto, cuando la aplicación muere, el servicio también se detendrá. Entonces, lo que puede hacer es enviar la transmisión desde el método onTaskRemoved de su servicio de la siguiente manera:

Intent intent = new Intent("com.android.ServiceStopped"); sendBroadcast(intent);

y tener un receptor de difusión que volverá a iniciar un servicio. Lo he intentado. El servicio se reinicia desde todo tipo de muertes.


el comando onstart interno pone START_STICKY ... Este servicio no se eliminará a menos que esté realizando demasiadas tareas y el núcleo quiera matarlo por ello ...

@Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("LocalService", "Received start id " + startId + ": " + intent); // We want this service to continue running until it is explicitly // stopped, so return sticky. return START_STICKY; }


Todas las respuestas parecen correctas, así que seguiré y daré una respuesta completa aquí.

En primer lugar, la forma más sencilla de hacer lo que está intentando hacer es iniciar una difusión en Android cuando la aplicación se elimina manualmente, y definir un BroadcastReceiver personalizado para activar un reinicio del servicio después de eso.

Ahora vamos a saltar en el código.

Crea tu Servicio en YourService.java

Tenga en cuenta el método onCreate() , donde estamos iniciando un servicio de primer plano de manera diferente para versiones de Build superiores a Android Oreo . Esto se debe a las estrictas políticas de notificación introducidas recientemente en las que tenemos que definir nuestro propio canal de notificación para mostrarlas correctamente.

El this.sendBroadcast(broadcastIntent); en el método onDestroy() está la declaración que envía de forma asíncrona una difusión con el nombre de la acción "restartservice" . Usaremos esto más adelante como un desencadenante para reiniciar nuestro servicio.

Aquí hemos definido una tarea de temporizador simple, que imprime un valor de contador cada 1 segundo en el Log y se incrementa cada vez que se imprime.

public class YourService extends Service { public int counter=0; @Override public void onCreate() { super.onCreate(); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) startMyOwnForeground(); else startForeground(1, new Notification()); } @RequiresApi(Build.VERSION_CODES.O) private void startMyOwnForeground() { String NOTIFICATION_CHANNEL_ID = "example.permanence"; String channelName = "Background Service"; NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE); chan.setLightColor(Color.BLUE); chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); assert manager != null; manager.createNotificationChannel(chan); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID); Notification notification = notificationBuilder.setOngoing(true) .setContentTitle("App is running in background") .setPriority(NotificationManager.IMPORTANCE_MIN) .setCategory(Notification.CATEGORY_SERVICE) .build(); startForeground(2, notification); } @Override public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); startTimer(); return START_STICKY; } @Override public void onDestroy() { super.onDestroy(); stoptimertask(); Intent broadcastIntent = new Intent(); broadcastIntent.setAction("restartservice"); broadcastIntent.setClass(this, Restarter.class); this.sendBroadcast(broadcastIntent); } private Timer timer; private TimerTask timerTask; public void startTimer() { timer = new Timer(); timerTask = new TimerTask() { public void run() { Log.i("Count", "========= "+ (counter++)); } }; timer.schedule(timerTask, 1000, 1000); // } public void stoptimertask() { if (timer != null) { timer.cancel(); timer = null; } } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }

Cree un receptor de difusión para responder a sus difusiones personalizadas definidas en Restarter.java

Ahora se supone que la transmisión con el nombre de la acción "restartservice" que acaba de definir en YourService.java un método que reiniciará su servicio . Esto se hace utilizando BroadcastReceiver en Android.

onRecieve() método onRecieve() incorporado en BroadcastReceiver para agregar la declaración que reiniciará el servicio. El servicio de startService() no funcionará según lo previsto en y sobre Android Oreo 8.1, ya que las políticas de fondo estrictas terminarán pronto el servicio después del reinicio una vez que se elimine la aplicación. Por lo tanto, utilizamos startForegroundService() para versiones superiores y mostramos una notificación continua para mantener el servicio en ejecución.

public class Restarter extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.i("Broadcast Listened", "Service tried to stop"); Toast.makeText(context, "Service restarted", Toast.LENGTH_SHORT).show(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(new Intent(context, YourService.class)); } else { context.startService(new Intent(context, YourService.class)); } } }

Defina su MainActivity.java para llamar al servicio en el inicio de la aplicación.

Aquí definimos un método isMyServiceRunning() separado para verificar el estado actual del servicio en segundo plano. Si el servicio no se está ejecutando, lo iniciamos usando startService() .

Dado que la aplicación ya se está ejecutando en primer plano, no necesitamos iniciar el servicio como un servicio en primer plano para evitar que se finalice.

Tenga en cuenta que en onDestroy() estamos llamando stopService() a stopService() , para que se invoque nuestro método anulado . Si esto no se hubiera hecho, entonces el servicio habría finalizado automáticamente después de que la aplicación se onDestroy() sin invocar nuestro método onDestroy() modificado en YourService.java

public class MainActivity extends AppCompatActivity { Intent mServiceIntent; private YourService mYourService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mYourService = new YourService(); mServiceIntent = new Intent(this, mYourService.getClass()); if (!isMyServiceRunning(mYourService.getClass())) { startService(mServiceIntent); } } private boolean isMyServiceRunning(Class<?> serviceClass) { ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (serviceClass.getName().equals(service.service.getClassName())) { Log.i ("Service status", "Running"); return true; } } Log.i ("Service status", "Not running"); return false; } @Override protected void onDestroy() { stopService(mServiceIntent); super.onDestroy(); } }

Finalmente registralos en tu AndroidManifest.xml

Las tres clases anteriores deben registrarse por separado en AndroidManifest.xml .

Tenga en cuenta que definimos un intent-filter con el nombre de la acción como "restartservice" en el que Restarter.java está registrado como receiver . Esto garantiza que se llame a nuestro BroadcastReciever personalizado cada vez que el sistema encuentre una difusión con el nombre de acción dado.

<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <receiver android:name="Restarter" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="restartservice" /> </intent-filter> </receiver> <activity android:name="MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="YourService" android:enabled="true" > </service> </application>

Esto ahora debería reiniciar su servicio nuevamente si la aplicación se eliminó del administrador de tareas. Este servicio continuará ejecutándose en segundo plano siempre que el usuario no Force Stop la Force Stop la aplicación desde la Configuración de la aplicación .