Cancel notification on remove application from multitask panel

前端 未结 7 1717
北恋
北恋 2020-11-27 14:15

I manage an ONGOING notification from my application (not from a service).

When I kill application from task manager with \"End\" button, no

相关标签:
7条回答
  • 2020-11-27 15:00

    The ability to swipe apps out of the recent apps list is introduced in Ice Cream Sandwich (API-14).

    With the same Android version, we received a special method "onTaskRemoved()" in "android.app.Service". It is get invoked when app is removed from recent apps list.

    So, just override "onTaskRemoved()" method to achieve your requirements if you are having any service running.

    E.g.:

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

    Or simply write & start special service to manage the same.

    0 讨论(0)
  • 2020-11-27 15:00

    You shoud create class extends Application and register activity callbacks, whose call when you close application from multitask pannel.

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

    }

    0 讨论(0)
  • 2020-11-27 15:00

    The question is old but it may help others.

    As pointed by others, you can use onTaskRemoved() but it is not called on many devices like Xiaomi, Oppo and other Chinese manufacturers', unless the app is added to whitelist.

    To support these devices too, service can be started in foreground. This way, notification is attached to the service. So, the notification will be cleared when the service is killed (by swipping in the multitask panel).

    0 讨论(0)
  • 2020-11-27 15:10

    I would suggest You to use Deepti solution (https://stackoverflow.com/a/28584405/619673) which was

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

    However, he forget mention one thing. If Your connection to service was by call bindService(), onTaskRemoved() won't be trigged. To handle this You must connect with service by call startService() as in example below:

    startService(new Intent(context, CustomerService.class));
    

    Once You call it, You will be able catch onTaskRemoved().

    Nothing stands in the way to call both methods startService() and somewhere further bindService().


    I was basing on solution Service: onTaskRemoved not called if started with bindService

    startService(new Intent(context, CustomerService.class)); // this will allow catch onTaskRemoved
    // ...
    bindService(new Intent(context, CustomerService.class),
                            mConnection, Context.BIND_AUTO_CREATE);
    
    0 讨论(0)
  • 2020-11-27 15:13

    Killing Notifications when main app has been killed.

    Since your notification and your app are handled in different threads killing your app via MultitaskManager won't kill your notification. As you already correctly investigated killing your app won't even necesarrily result in an onExit() callback.

    So what is the solutions?

    You could start a service from your activity. A specialty services have: they restart themselves automatically if app-process have been killed for some reason. So you could reuse the automatic restart by killing the notification on restart.

    Step 1 create a service that kills Simple one. It just kills a notification on create and has his special Binder.

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

    Step2: Add it to your manifest: Add it somewhere inbetween your <application> tags.

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

    Step3: Always create the Service before fireing the notification, and use the static notificationid.

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

    It might take a little time until service is restarted (1-5 sec), but it will eventually start and kill the notification.

    0 讨论(0)
  • I have the same problem myself however I managed to fix it

    This is what I did

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

    If you hold the home button for 2-3 seconds then the multipane comes to the foreground while our activity is currently in the pause state. Therefore we need to bring it to the foreground first and then remove the app notification and finally exit the app

    destroyActivityCompletely function will remove the app notification and then kill the activity. This will work if the activity is excited from multipane and etc.

    0 讨论(0)
提交回复
热议问题