我从我的应用程序(而不是服务)管理 ONGOING 通知。
当我使用“结束”按钮从任务管理器中删除应用程序时,通知消失。
当我从多任务面板移除应用程序时,应用程序被终止,但通知仍然。
我的问题是:
作为更新:
我的所有活动都使用以下方法扩展了MyActivity类(扩展了Activity):
@Override protected void onCreate(Bundle state) {
super.onCreate(state);
((MyApplication) getApplication()).onActivityCreate(this, state);
}
@Override protected void onDestroy() {
super.onDestroy();
((MyApplication) getApplication()).onActivityDestroy(this);
}
我的应用程序使用以下方法扩展了MyApplication类(扩展了Application):
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
是所有正在运行的活动的列表
这不是最简单的机制,但我需要它
我应该使用服务吗?
作为新的更新:
在我的onExit()方法中,如果我记录调试消息,知道会发生什么:
public void onExit() {
for(int i = 0; i < 100; i++) {
Log.d(TAG, "onExit");
}
}
少量日志出现在两个,而不是全部(例如:13/100)
所以,我明白从多任务pannel强制删除应用程序以杀死应用程序而不等待关闭方法结束正确...但为什么不处理?!
如何强行终止?
答案 0 :(得分:41)
杀死主应用时的通知。
由于您的通知和应用程序是在不同的线程中处理的,因此通过MultitaskManager杀死您的应用程序不会终止您的通知。正如你已经正确调查过,杀死你的应用程序甚至不会导致onExit()回调。
那么解决方案是什么?
您可以从您的活动中启动服务。专业服务有:如果app-process因某种原因被杀,他们会自动重启。因此,您可以通过在重新启动时终止通知来重用自动重启。
步骤1创建一个杀死的服务 简单的一个。它只是杀死了关于创建的通知并且有他特殊的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);
}
}
第2步:将其添加到您的清单 将它添加到您的&lt; application&gt;之间的某个位置标签
<service android:name="KillNotificationsService"></service>
步骤3:在触发通知之前始终创建服务,并使用静态通知。
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);
重新启动服务(1-5秒)可能需要一点时间,但最终会启动并终止通知。
答案 1 :(得分:35)
Ice Cream Sandwich(API-14)引入了将应用程序从最近的应用列表中滑出的功能。
使用相同的Android版本,我们在“android.app.Service”中收到了一个特殊方法“onTaskRemoved()”。从最近的应用列表中删除应用时会调用它。
因此,如果您正在运行任何服务,只需覆盖“onTaskRemoved()”方法即可实现您的要求。
E.g:
@Override
public void onTaskRemoved(Intent rootIntent) {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel(NOTIFICATION_ID);
}
或简单地写&amp;开始特殊服务来管理同样的事情。
答案 2 :(得分:12)
你应该创建类扩展应用程序和注册活动回调,当你从多任务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);
}
}
});
}
}
答案 3 :(得分:0)
我自己也有同样的问题,但我设法解决了这个问题
这就是我做的事情
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;
}
}
如果按住主屏幕按钮2-3秒,当我们的活动当前处于暂停状态时,多重窗格会到达前台。因此,我们需要先将其置于前台,然后删除应用程序通知,最后退出应用程序
destroyActivityCompletely函数将删除应用程序通知,然后终止活动。如果从多窗格等激活活动,这将有效。
答案 4 :(得分:0)
我想关闭我的所有应用程序通知,删除注销图标,从最近的应用程序列表中删除。对于
Xamarin.Android
启动器活动时启动服务(我正在从此处创建通知)为
Intent intent = new Intent(this, typeof(PushNotificationService));
this.StartService(intent);
其中PushNotificationService
是我的Android service
,其中我有
[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)
{
}
}
}
OnTaskRemoved(Intent rootIntent)
中的这一行起到了作用
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Cancel(0);
其中notificationManager.Cancel(0);
中的0是我们在构建通知时放入的本地通知ID。
答案 5 :(得分:0)
我建议您使用
的Deepti解决方案(https://stackoverflow.com/a/28584405/619673)。@Override
public void onTaskRemoved(Intent rootIntent) {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel(NOTIFICATION_ID);
}
但是,他忘记提及一件事。如果您通过呼叫bindService()
与服务建立连接,则不会触发onTaskRemoved()
。要解决此问题,您必须通过调用startService()
与服务进行连接,如下例所示:
startService(new Intent(context, CustomerService.class));
一旦您调用它,便可以捕获onTaskRemoved()
。
没有什么办法可以同时调用两个方法startService()
和其他任何地方bindService()
。
我基于解决方案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);
答案 6 :(得分:0)
这个问题很古老,但可能会帮助别人。
正如其他人所指出的那样,您可以使用onTaskRemoved(),但是除非小程序,Oppo和其他中国制造商的设备在很多设备上都没有调用它,除非将该应用程序添加到白名单中。
为了也支持这些设备,可以在前台启动服务。这样,通知将附加到服务。因此,当服务被终止时(通过在多任务面板中滑动),通知将被清除。
答案 7 :(得分:0)
我发现 AndacAydin 在 13 年 1 月接受的答案对我来说效果很好。但是,在 21 年 1 月 (API 30) 中已经发生了足够的变化,需要进行一些修订。
“第 3 步:在触发之前总是创建服务......”需要修改,主要是因为通知中的“setLatestEventInfo”方法不仅被弃用,而且实际上被删除了!
这是我对他的第 3 步的更新,现在在 R 中对我来说效果很好:
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder binder) {
((KillBinder) binder).service.startService(new Intent(
MainActivity.this, KillNotificationsService.class));
Intent notificationIntent = new Intent(getApplicationContext(),
MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(
MainActivity.this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(
getApplicationContext(), "someChannel")
.setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(contentIntent)
.build();
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);