安卓:只在离开应用程序时显示状态栏通知

3
我有一个包含四个活动的应用程序,在应用程序中,用户将不断地浏览这四个活动。此外,该应用程序还有一个在后台运行的持续服务,该服务显示状态栏通知,并监听内容更改,然后在通知中显示相应的内容。
目前,当用户开始需要显示通知的操作时,服务会显示通知,因此,即使您仍在使用应用程序,通知也会显示。期望的情况是仅在用户导航出应用程序时显示通知。
我尝试重写生命周期方法,如下所示:
    @Override
protected void onPause() {  
    Intent intent = new Intent();
    intent.setAction(MyService.ACTION_DISPLAY_PENDING_NOTIFICATION);
    sendBroadcast(intent);
    super.onPause();
}

@Override
protected void onResume() { 
    super.onResume();
    Intent intent = new Intent();
    intent.setAction(MyService.ACTION_CANCEL_NOTIFICATION);
    sendBroadcast(intent);      
}

这项服务的流程如下:

@Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (action.equals(ACTION_DISPLAY_PENDING_NOTIFICATION)) {
            showNotification();
        }

        else if (action.equals(ACTION_CANCEL_NOTIFICATION)) {
            mNotificationManager.cancel(mNotId);
        }
    }

这个功能可以实现。但是,由于当用户从一个活动中导航离开时发送意图,我在用户浏览4个活动时遇到了不希望出现的行为和轻微的性能问题。即使在从活动A到活动B或任何4个活动的组合时,服务也会尝试显示通知。

通知会立即被取消,因为当新的Activity B启动时,它将在onResume期间调用mNotificationManager.cancel(mNotifId),但由于在离开Activity A时告诉服务执行此操作,因此通知已经构建并显示了一小部分时间。我想解决的是这种行为,而不是无谓地构建和显示这些通知,

有没有办法可以知道用户何时离开活动到另一个应用程序,例如主页等;但不是在应用程序内部?

编辑

仅澄清,在onPause方法中,活动必须检查两件事情,

a)前台是否有任何先前的活动?为什么?因为用户可能通过按返回键来导航离开活动,这意味着堆栈上显示最后一个活动。为了检查这一点,DennisDrew的答案可以起作用,我们可以这样检查:

if(!ForegroundHelper.activityExistsInForeground()){
//show your notification
}

但这不是用户唯一可以导航离开该活动的方式,用户也可以按Home键,这种情况下,无论activityExistsInForeground()的评估结果是真还是假,通知都应该显示。
b) 用户是否要进入应用程序中的另一个活动?例如,用户正在Activity A上,在当前前台仅有该活动时,用户单击启动Activity B的UI元素。尽管activityExistsInForeground()评估为false,但用户并没有离开应用程序,而是启动了之前未在前台的活动的新实例。
我尝试添加标志,例如默认值为private boolean launchingNewActivity = false,并在我知道自己要进入另一个活动时将标志设置为true,例如在我的listview上单击项时:
litview.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {
            launchingNewActivity = true
            startActivity2(arg2);
        }           
    });

然后在onPause期间检查它:

@Override
protected void onPause() {
    if(!ForegroundHelper.activityExistsInForeground() && launchingNewActivity){
    //show your notification        
}

但是这样做,它从来不会显示通知,不知何故双重检查总是默认为false。


请查看此网址:https://dev59.com/2G025IYBdhLWcg3wfmDw - Waqas
那并不完全适用,因为它假设用户在按“返回”按钮。 - daniel_c05
@daniel_c05 在你的onPause()方法中的"if"语句里,你的判断应该是这样的... if(!(ForegroundHelper.activityExistsInForeground() || launchingNewActivity)) - dennisdrew
2个回答

3
如果您使用单例引用会怎样呢?您可以创建一个类如下:
```java public class Singleton { private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return instance; } } ```
这个类只有一个实例,可以全局访问。
public static class ForegroundHelper {
    public static boolean[] activityStates = new boolean{false, false, false, false};
    public static final int ACTIVITY_A = 0;
    public static final int ACTIVITY_B = 1;
    public static final int ACTIVITY_C = 2;
    public static final int ACTIVITY_D = 3;

    public static boolean activityExistsInForeground(){
        for(boolean b : activityStates){
            if(b)
                return true;
        }

        return false;
    }
}

然后,在每个活动的onResume()中执行以下操作:
//For your first activity (Activity A)
ForegroundHelper.activityStates[ForegroundHelper.ACTIVITY_A] = true;

在每个活动的onPause()方法中执行以下操作:

ForegroundHelper.activityStates[ForegroundHelper.ACTIVITY_A] = false;

在每个活动的onStop()方法中执行以下操作:

if(!ForegroundHelper.activityExistsInForeground()){
    //show your notification
}

顺便说一下,我以前从来没有做过这样的事情,所以我不知道它是否会像我编码的那样完全起作用...但如果这有帮助,请告诉我。


这实际上是有效的,但只是部分有效。为什么?因为它假设用户在当前活动中按下了返回键,如果用户从A到B,即使B、C、D甚至A都不在前台,用户也没有导航出去,实际上是进入另一个活动。 - daniel_c05
我在问题中添加了更多的解释。 - daniel_c05
1
我猜这是最接近准确答案的了。谢谢。 - daniel_c05

2
我为此所做的是扩展应用程序类,并将“topActivity”保留在其中。我会在每个onResume / onPause方法中设置它,如下所示:
public class myApp extends Application{

   private Activity topActivity;
}

现在在每个活动中
@Override
protected void onResume() {

((myApp) getApplication()).setOnTopActivity(this);
}

@Override
    protected void onPause() {
        ((myApp) getApplication()).setOnTopActivity(null);
        super.onPause();
    }

这样,当应用程序不可见时,topActivity 为 null。因此,在显示通知之前,只需检查 topActivity==null 是否成立。如果是,您的应用程序不在前台,可以显示通知。

如果您无法访问应用程序类,则始终可以以静态方式存储此值 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接