Cancelar la notificación al eliminar la aplicación del panel multitarea

Administro una notificación EN CURSO desde mi aplicación (no desde un servicio).

Cuando elimino la aplicación del administrador de tareas con el botón “Finalizar”, la notificación desaparece .

Cuando elimino la aplicación del panel multitarea, la aplicación se cancela pero la notificación permanece .

Mis preguntas son:

  • Cómo atrapar este evento para borrar la notificación?
  • ¿Qué sucede cuando la aplicación se elimina del panel multitarea? La aplicación se destruye pero el proceso se mantiene vivo? ¿Es normal?

Como una actualización:

Todas mis actividades amplían la clase MyActivity (que amplía la Actividad) con métodos:

@Override protected void onCreate(Bundle state) { super.onCreate(state); ((MyApplication) getApplication()).onActivityCreate(this, state); } @Override protected void onDestroy() { super.onDestroy(); ((MyApplication) getApplication()).onActivityDestroy(this); } 

Y mi aplicación extiende la clase MyApplication (que extiende la aplicación) con métodos:

 private List activities = new ArrayList(); protected final void onActivityCreate(Activity activity, Bundle state) { if(activities.isEmpty() && state == null) { onStart(); } activities.add(activity); } protected final void onActivityDestroy(Activity activity) { activities.remove(activity); if(activities.isEmpty() && activity.isFinishing()) { onExit(); } } protected void onStart() { // some code } protected void onExit() { // some code notificationManager.cancel(NOTIFICATION_ID); } 

activities es una lista de todas las actividades en ejecución

No es el mecanismo más simple, pero lo necesito

¿Debo usar un servicio en su lugar?


Como una nueva actualización:

En mi método onExit (), si registro un mensaje de depuración para saber qué sucede así:

 public void onExit() { for(int i = 0; i < 100; i++) { Log.d(TAG, "onExit"); } } 

aparece una pequeña cantidad de registro una vez en dos, no en todos (ej: 13/100)

Por lo tanto, entiendo que elimine la aplicación de la fuerza del panel multitarea para eliminar la aplicación sin esperar a que los métodos de cierre terminen correctamente … ¿Pero por qué no procesar?

¿Cómo puedo obligar a terminar adecuadamente?

Matar notificaciones cuando la aplicación principal ha sido eliminada.

Como su notificación y su aplicación se manejan en diferentes hilos, matar su aplicación a través de MultitaskManager no matará su notificación. Como ya investigaste correctamente, matar tu aplicación no necesariamente dará como resultado una callback onExit ().

Entonces, ¿cuáles son las soluciones?

Podría comenzar un servicio de su actividad. Los servicios especializados tienen: se reinician automáticamente si el proceso de la aplicación ha sido cancelado por alguna razón. Para poder reutilizar el reinicio automático, cancela la notificación al reiniciar.

Paso 1 crea un servicio que mata Simple. Simplemente mata una notificación en create y tiene su Binder especial.

 public class KillNotificationsService extends Service { public class KillBinder extends Binder { public final Service service; public KillBinder(Service service) { this.service = service; } } public static int NOTIFICATION_ID = 666; private NotificationManager mNM; private final IBinder mBinder = new KillBinder(this); @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public int onStartCommand(Intent intent, int flags, int startId) { return Service.START_STICKY; } @Override public void onCreate() { mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mNM.cancel(NOTIFICATION_ID); } } 

Paso 2: agrégalo a tu manifiesto: agrégalo en algún lugar entre las tags de tu .

  

Paso 3: crea siempre el servicio antes de activar la notificación y utiliza el ID de notificación estático.

 ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder binder) { ((KillBinder) binder).service.startService(new Intent( MainActivity.this, KillNotificationsService.class)); Notification notification = new Notification( R.drawable.ic_launcher, "Text", System.currentTimeMillis()); Intent notificationIntent = new Intent(MainActivity.this, Place.class); PendingIntent contentIntent = PendingIntent.getActivity( MainActivity.this, 0, notificationIntent, 0); notification.setLatestEventInfo(getApplicationContext(), "Text", "Text", contentIntent); NotificationManager mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mNM.notify(KillNotificationsService.NOTIFICATION_ID, notification); } public void onServiceDisconnected(ComponentName className) { } }; bindService(new Intent(MainActivity.this, KillNotificationsService.class), mConnection, Context.BIND_AUTO_CREATE); 

Puede tomar un poco de tiempo hasta que se reinicie el servicio (1-5 segundos), pero eventualmente comenzará y matará la notificación.

La capacidad de deslizar aplicaciones fuera de la lista de aplicaciones recientes se presenta en Ice Cream Sandwich (API-14).

Con la misma versión de Android, recibimos un método especial “onTaskRemoved ()” en “android.app.Service”. Se invoca cuando la aplicación se elimina de la lista de aplicaciones recientes.

Por lo tanto, simplemente anule el método “onTaskRemoved ()” para cumplir sus requisitos si tiene algún servicio en ejecución.

P.ej:

 @Override public void onTaskRemoved(Intent rootIntent) { NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mNotificationManager.cancel(NOTIFICATION_ID); } 

O simplemente escriba e inicie un servicio especial para administrar el mismo.

Debes crear clases para extender solicitudes y registrar devoluciones de llamadas de actividades, cuya llamada se realiza al cerrar la aplicación desde el panel multitarea.

  public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle bundle) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { if (/*check is all your activities onStop state*/) { NotificationManager mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mNM.cancel(R.id.key_notification_id); } } }); } 

}

Tengo el mismo problema, sin embargo, logré solucionarlo

Esto es lo que hice

  public class Sample extends Activity { private static final String APP_NOTIFICATION_TAG = "sample"; private static final int NOTIFICATION_ID = 24; private NotificationManager notificationManager; private Notification appNotification; private AppFinishedExecutingListener appFinishedExecutingListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // set the layout and other stuff goes here appFinishedExecutingListener.execute(this); new Thread() { @Override public void run() { try { appFinishedExecutingListener.get(); handler.post(new Runnable() { @Override public void run() { destroyActivityComponent(); } }); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }.start(); setupNotification(); } /* * Setup this app */ private void setupNotification() { Intent intent = new Intent(getApplicationContext(), MainActivity.class); // make sure when the user click the notification, this will make sure it will resume the app intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); // define the action should be performed if the user click the notification ie resume our app activity PendingIntent pIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), intent, 0); // setup the look for this app on a notification panel appNotification = new NotificationCompat.Builder(this) .setContentTitle(getString(R.string.app_name)) .setContentText("Currently listening to kiribati radio") .setSmallIcon(R.drawable.ic_notification_logo) .setContentIntent(pIntent) .setAutoCancel(true) .setOngoing(true).build() ; notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); } /* * Will add app notification when this activity is paused so the user can * quickly access it or resume this activity easily */ private void addAppToNotificationP() { notificationManager.notify(APP_NOTIFICATION_TAG, NOTIFICATION_ID, appNotification); } /* * This will remove the notification if this activity is resumed */ private void removeAppFromNotificationP() { notificationManager.cancel(APP_NOTIFICATION_TAG,NOTIFICATION_ID); } @Override protected void onPause() { super.onPause(); addAppToNotificationP(); } @Override protected void onResume() { super.onResume(); removeAppFromNotificationP(); } private void destroyActivityCompletely() { onResume(); finish(); } } public class AppFinishedExecutingListener extends AsyncTask { private MainActivity main_activity; @Override protected Boolean doInBackground(MainActivity... params) { main_activity = params[0]; while(!main_activity.isFinishing()) { try { Thread.sleep(100); //Log.i(main_activity.TAG,"listening"); } catch (InterruptedException e) { e.printStackTrace(); } } //main_activity.finish(); return true; } } 

Si mantiene presionado el botón de inicio durante 2-3 segundos, el multipane se pone en primer plano mientras nuestra actividad se encuentra actualmente en estado de pausa. Por lo tanto, primero debemos ponerlo en primer plano y luego eliminar la notificación de la aplicación y, finalmente, salir de la aplicación

La función destroyActivityCompletely eliminará la notificación de la aplicación y luego matará la actividad. Esto funcionará si la actividad se emociona de multipane y etc.