Ich verwalte eineLAUFENDEBenachrichtigung von meiner Anwendung (nicht von einem Dienst).
Wenn ich die Anwendung vom Task-Manager mit der Schaltfläche "Beenden" abschalte, verschwindet Benachrichtigung .
Wenn ich die Anwendung aus dem Multitask-Bereich entferne, wird die Anwendung abgebrochen, aber Benachrichtigung bleibt erhalten .
Meine Fragen sind:
Als Update:
Alle meine Aktivitäten erweitern die MyActivity-Klasse (die Activity erweitert) um Methoden:
@Override protected void onCreate(Bundle state) {
super.onCreate(state);
((MyApplication) getApplication()).onActivityCreate(this, state);
}
@Override protected void onDestroy() {
super.onDestroy();
((MyApplication) getApplication()).onActivityDestroy(this);
}
Und meine Anwendung erweitert die MyApplication-Klasse (die die Anwendung erweitert) um Methoden:
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
ist eine Liste aller laufenden Aktivitäten
Es ist nicht der einfachste Mechanismus, aber ich brauche ihn
Soll ich stattdessen einen Dienst nutzen?
Als neues Update:
Wenn ich in meiner onExit () -Methode eine Debug-Nachricht protokolliere, um zu wissen, was passiert, so:
public void onExit() {
for(int i = 0; i < 100; i++) {
Log.d(TAG, "onExit");
}
}
eine kleine Menge Protokoll erscheint einmal auf zwei, nicht auf allen (Beispiel: 13/100)
Also, ich verstehe, dass die Anwendung aus dem Multitask-Bereich entfernt wird, um die Anwendung zu beenden, ohne zu warten, dass die Schließen-Methoden ordnungsgemäß beendet werden ... Aber warum nicht verarbeiten?
Wie kann ich eine ordentliche Beendigung erzwingen?
Benachrichtigungen abbrechen, wenn die Hauptanwendung beendet wurde.
Da Ihre Benachrichtigung und Ihre App in verschiedenen Threads verarbeitet werden, wird das Beenden Ihrer App über MultitaskManager Ihre Benachrichtigung nicht beenden. Wie Sie bereits richtig untersucht haben, führt das Töten Ihrer App nicht unbedingt zu einem Aufruf von onExit ().
Was sind die Lösungen?
Sie können einen Dienst aus Ihrer Aktivität starten. Eine Spezialität hat Folgendes: Sie starten sich automatisch neu, wenn der App-Prozess aus irgendeinem Grund beendet wurde. So können Sie den automatischen Neustart wiederverwenden, indem Sie die Benachrichtigung beim Neustart abbrechen.
Schritt 1: Erstellen Sie einen Dienst, der .__ abtötet. Einfach. Es zerstört nur eine Benachrichtigung beim Erstellen und hat seine spezielle Sammelmappe.
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);
}
}
Schritt2: Fügen Sie es Ihrem Manifest hinzu: Fügen Sie es irgendwo zwischen Ihren <application> -Tags ein.
<service Android:name="KillNotificationsService"></service>
Schritt 3: Erstellen Sie immer den Dienst, bevor Sie die Benachrichtigung auslösen, und verwenden Sie die statische Benachrichtigungs-ID.
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);
Es kann etwas dauern, bis der Dienst neu gestartet wird (1-5 Sek.), Aber es wird eventuell gestartet und die Benachrichtigung beendet.
Die Möglichkeit, Apps aus der Liste der zuletzt verwendeten Apps herauszuziehen, wurde in Ice Cream Sandwich (API-14) eingeführt.
Mit derselben Android-Version haben wir in "Android.app.Service" eine spezielle Methode "onTaskRemoved ()" erhalten. Sie wird aufgerufen, wenn die App aus der Liste der letzten Apps entfernt wird.
Überschreiben Sie einfach die "onTaskRemoved ()" -Methode, um Ihre Anforderungen zu erfüllen, wenn ein Dienst ausgeführt wird.
Z.B.:
@Override
public void onTaskRemoved(Intent rootIntent) {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel(NOTIFICATION_ID);
}
Oder schreiben Sie einfach einen speziellen Service, um das gleiche zu verwalten.
Sie sollten eine Klasse erstellen, die die Anwendung erweitert und Aktivitäts-Callbacks registriert.
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);
}
}
});
}
}
Ich würde vorschlagen, dass Sie Deepti-Lösung ( https://stackoverflow.com/a/28584405/61967 ) verwenden, die war
@Override
public void onTaskRemoved(Intent rootIntent) {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel(NOTIFICATION_ID);
}
Er hat jedoch vergessen, eine Sache zu erwähnen. Wenn Ihre Verbindung zum Dienst per Anruf hergestellt wurde, wird bindService()
, onTaskRemoved()
nicht ausgelöst. Um dies zu handhaben, müssen Sie eine Verbindung mit dem Dienst herstellen, indem Sie startService()
wie im folgenden Beispiel aufrufen:
startService(new Intent(context, CustomerService.class));
Sobald Sie es aufrufen, können Sie onTaskRemoved()
fangen.
Beiden Methoden startService()
und irgendwo weiteren bindService()
steht nichts im Wege.
Ich basierte auf Lösung Service: onTaskRemoved nicht aufgerufen, wenn mit bindService gestartet
startService(new Intent(context, CustomerService.class)); // this will allow catch onTaskRemoved
// ...
bindService(new Intent(context, CustomerService.class),
mConnection, Context.BIND_AUTO_CREATE);
Ich habe selbst das gleiche Problem, aber es ist mir gelungen, es zu beheben
Das habe ich getan
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;
}
}
Wenn Sie die Home-Taste für 2-3 Sekunden gedrückt halten, tritt der Multipane in den Vordergrund, während sich unsere Aktivität gerade im Pause-Zustand befindet. Deshalb müssen wir es zuerst in den Vordergrund bringen, dann die App-Benachrichtigung entfernen und die App schließlich beenden
die Funktion destroyActivityCompletely entfernt die App-Benachrichtigung und beendet dann die Aktivität. Dies funktioniert, wenn die Aktivität von Multipane usw. angeregt wird.
Die Frage ist alt, kann aber anderen helfen.
Wie bereits von anderen erwähnt, können Sie onTaskRemoved () verwenden, aber es wird auf vielen Geräten wie Xiaomi, Oppo und anderen chinesischen Herstellern nicht aufgerufen, es sei denn, die App wurde zur Whitelist hinzugefügt.
Um auch diese Geräte zu unterstützen, kann der Service im Vordergrund gestartet werden. Auf diese Weise wird eine Benachrichtigung an den Dienst angehängt. Die Benachrichtigung wird also gelöscht, wenn der Dienst beendet wird (durch Wischen im Multitask-Bereich).
Ich wollte alle App-Benachrichtigungen schließen, Badge-Symbole beim Abmelden entfernen und aus der Liste der letzten Apps entfernen. so für
Xamarin.Android
dienst am Startprogramm starten (Ich erstelle hier eine Benachrichtigung) als
Intent intent = new Intent(this, typeof(PushNotificationService));
this.StartService(intent);
wobei PushNotificationService
mein Android service
ist, in dem ich bin
[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)
{
}
}
}
diese Zeile in OnTaskRemoved(Intent rootIntent)
hat den Trick ausgeführt
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Cancel(0);
dabei ist 0 in notificationManager.Cancel(0);
die lokale Benachrichtigungs-ID, die wir zum Zeitpunkt der Erstellung der Benachrichtigung setzen.