web-dev-qa-db-fra.com

Annuler la notification lors de la suppression de l'application du panneau multitâche

Je gère une notification EN COURS depuis mon application (et non depuis un service).

Lorsque je tue une application du gestionnaire de tâches avec le bouton "Terminer", notification disparaît.

Lorsque je supprime une application du panneau multitâche, l’application est supprimée, mais notification reste.

Mes questions sont:

  • Comment attraper cet événement pour effacer la notification?
  • Que se passe-t-il lorsque l'application est supprimée du panneau multitâche? L'application est détruite mais le processus reste en vie? Est-ce normal?

Comme mise à jour:

Toutes mes activités étend la classe MyActivity (qui étend Activity) avec les méthodes suivantes:

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

@Override protected void onDestroy() {
    super.onDestroy();
    ((MyApplication) getApplication()).onActivityDestroy(this);
}

Et mon application étend la classe MyApplication (qui étend Application) avec les méthodes suivantes:

private List<Activity> activities = new ArrayList<Activity>();

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 est une liste de toutes les activités en cours

Ce n'est pas le mécanisme le plus simple mais j'en ai besoin

Devrais-je utiliser un service à la place?


En tant que nouvelle mise à jour:

Dans ma méthode onExit (), si je me connecte un message de débogage pour savoir ce qui se passe comme ceci:

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

une petite quantité de log apparaît une fois sur deux, pas toutes (ex: 13/100)

Donc, je comprends que supprimer l’application de la force du panneau multitâche pour tuer l’application sans attendre que les méthodes proches se terminent correctement… Mais pourquoi ne pas traiter?

Comment puis-je forcer à terminer correctement?

40
alex

Tuer des notifications lorsque l'application principale a été tué.

Étant donné que votre notification et votre application sont traitées dans différents threads, tuer votre application via MultitaskManager ne tue pas votre notification. Comme vous avez déjà correctement enquêté, tuer votre application ne provoquera même pas nécessairement un rappel onExit ().

Alors, quelles sont les solutions?

Vous pouvez démarrer un service à partir de votre activité. Les services spécialisés ont: ils se redémarrent automatiquement si le processus d'application a été tué pour une raison quelconque. Vous pouvez donc réutiliser le redémarrage automatique en supprimant la notification au redémarrage.

Étape 1 créer un service qui tue Simple. Il tue simplement une notification sur create et possède son classeur spécial.

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);
    }
}

Étape 2: Ajoutez-le à votre manifeste: .__ Ajoutez-le quelque part entre vos balises <application>.

<service Android:name="KillNotificationsService"></service>

Étape 3: Créez toujours le service avant de lancer la notification et utilisez le notid statique.

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);

Le redémarrage du service peut prendre un peu de temps (1 à 5 secondes), mais il finira par démarrer et tuer la notification.

40
AndacAydin

La possibilité de faire glisser des applications de la liste des applications récentes est introduite dans Sandwich à la crème glacée (API-14).

Avec la même version Android, nous avons reçu une méthode spéciale "onTaskRemoved ()" dans "Android.app.Service". Il est appelé lorsque l'application est supprimée de la liste des applications récentes.

Donc, substituez simplement la méthode "onTaskRemoved ()" pour répondre à vos exigences si un service est en cours d'exécution.

Par exemple.:

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

Ou tout simplement écrire et démarrer un service spécial pour gérer les mêmes.

33
Deepti

Vous devez créer la classe étend l'application et enregistrer les rappels d'activité, dont l'appel lorsque vous fermez l'application à partir du panneau multitâche. 

    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);
            }
        }
    });
}

}

12
Roman Trokhymets

J'ai le même problème moi-même mais j'ai réussi à le résoudre

C'est ce que j'ai fait

 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 i.e. 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<MainActivity, Void, Boolean> {

    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 vous maintenez le bouton d'accueil enfoncé pendant 2 à 3 secondes, le multi-volet passe au premier plan alors que notre activité est actuellement en pause. Par conséquent, nous devons d'abord l'afficher au premier plan, puis supprimer la notification de l'application et enfin quitter l'application.

la fonction destroyActivityCompletely supprimera la notification de l'application, puis supprimera l'activité. Cela fonctionnera si l’activité est excitée à partir de plusieurs fenêtres, etc.

0
Kateti Reo Mareko

Je voulais fermer toutes les notifications de mon application, supprimer les icônes de badge sur Déconnexion, supprimées de la liste des applications récentes. donc pour 

Xamarin.Android

démarrer le service à l'activité du lanceur (je crée une notification à partir d'ici) en tant que 

Intent intent = new Intent(this, typeof(PushNotificationService));
this.StartService(intent);

PushNotificationService est mon Android service à l'intérieur duquel j'ai 

[Service]
    public class PushNotificationService : Service
        {
            public override IBinder OnBind(Intent intent)
            {
                return null;
            }

        public override void OnCreate()
        {
            base.OnCreate();
        }
        public override void OnTaskRemoved(Intent rootIntent)
        {
            try
            {
                var notificationManager = (NotificationManager)GetSystemService(NotificationService);
                notificationManager.Cancel(0);
                ME.Leolin.Shortcutbadger.ShortcutBadger.RemoveCount(Application.Context);
            }
            catch (System.Exception ex)
            {
            }
        }
    }

cette ligne dans OnTaskRemoved(Intent rootIntent) a fait l'affaire 

 var notificationManager = (NotificationManager)GetSystemService(NotificationService);
                notificationManager.Cancel(0);

où 0 dans notificationManager.Cancel(0); est l'id de notifcation local que nous avons mis au moment de la notification de construction. 

0
Annu