如何知道我的Android应用程序是否可见?

18

我有一个定时器,当它结束时会启动通知。但是我想只有在应用程序当前不可见时使用notificationManager触发通知,并且如果计时器在应用程序前台结束,则显示alertDialog。

我已经尝试过这个:

ActivityManager actMngr = (ActivityManager) ValeoMobileApplication.getContext().getSystemService(Activity.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningAppProcesses = actMngr.getRunningAppProcesses();
Tools.log("TimerBroadcastReceiver", "onReceive", "All running processes are listed below :");
for (RunningAppProcessInfo pi : runningAppProcesses) {
    //Check pi.processName and do your stuff
    //also check pi importance - check if process is in foreground or background
    Tools.log("TimerBroadcastReceiver", "onReceive", pi.processName + " importance = "+pi.importance);
    if(pi.processName.equalsIgnoreCase("MY_APP_PROCESS_NAME")){
        if (pi.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
            isApplicationInForeground = true;
        }
    }
}

但似乎无论应用程序是前台还是后台都没有关系。我该怎么做呢?


ProcessLifecycleOwner是最新的解决方案。 - S.R
4个回答

26
使用有序广播进行通知发送,如果应用程序在前台,则活动具有高优先级接收器,否则使用清单注册的接收器。
这种技术已经在这篇博客文章中介绍过。
更新于2018年1月4日:上述方法可以工作,但它涉及系统广播,对于大多数(单进程)应用程序来说不是一个好的选择。相反,可以使用事件总线(如LocalBroadcastManager,greenrobot's EventBus),它具有更好的性能和安全性。请参见使用LocalBroadcastManager的示例应用程序使用GreenRobot的EventBus的示例应用程序,两者都实现了这种模式。

3
如果您的主要活动是启动另一个新活动,则此方法效果不佳。此时,由于触发了onPause,反注册将会发生。但是,从最终用户的角度来看,应用程序仍然可见。 - Cheok Yan Cheng
据我所知,这种方法在Android Oreo中不再适用。因为现在无法通过清单文件注册隐式接收器。 - MyDogTom
1
@MyDogTom:这种方法仍然可行,因为您将使用显式“Intent”,而不是隐式“Intent”。话虽如此,现在有更好的方法(例如,事件总线)。 - CommonsWare

11

您可以通过以下方式检测应用程序是否可见:

在所有Activity中设置:

@Override
protected void onResume() {
    super.onResume();

    myVisibilityManager.setIsVisible(true);
}

@Override
protected void onPause() {
    myVisibilityManager.setIsVisible(false);

    super.onPause();
}

(这可能导致您定义一个超类,将此行为实现到所有活动中)

然后创建一个VisibilityManager(这只是非常基础的,您可能需要更高级的东西):

public class VisibilityManager {
    private boolean mIsVisible = false;

    public void setIsVisible(boolean visible) { 
         mIsVisible = visible; 
    }

    public boolean getIsVisible() {
         return mIsVisible;
    }
}

然后,在您的计时器线程中,当倒数计时达到零时:

if (VisibilityManager.getIsVisible()) {
    showAlertDialog();
}
else {
    showNotification();
}

编辑:但我甚至更喜欢CommonsWare在这个页面上描述的方法。它更加优雅。


CommonsWare的方法很聪明有趣。然而,这种方法很直接。我们可能想知道应用程序是否在其他地方处于前台。因此我选择了这个方法。 - rpattabi
VisibilityManager 中的方法和变量应该是静态的。 - Lester

0

在这种情况下,我建议您使用服务而不是活动。

服务在后台运行,如果正确启动,则不受活动生命周期的影响。

需要记住的一件重要事情是,当您返回到UI时,服务必须显式调用UI线程,否则您将收到ANR错误,因为UI线程不是线程安全的。

请阅读该文档,它应该能帮助您获得更好的解决方案!

希望这有所帮助。


-1

这是解决方案:

public static boolean uygulamaCalisiyormu(Context context)
    {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> islemler = activityManager.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo uygulamaIslemi : islemler)
        {
            if (uygulamaIslemi.processName.equals(context.getPackageName()))
            {
                if (uygulamaIslemi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE || uygulamaIslemi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
                {
                    return true;
                }
            }
        }
        return false;
    }


...
 if (uygulamaCalisiyormu(getApplicationContext()))
        {
            Log.d("asd","App Already Started");
        }
      else
        {
Log.d("asd","App Started");
}

编辑:如果您想检查特定的活动(类),请使用以下内容;

  if (uygulamaIslemi.processName.equals("com.TRSoft.timetab:PIN"))
            {
                if (uygulamaIslemi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE || uygulamaIslemi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) // Lanet olasıca şey Visible ile Foreground arasındaki fark ne oç illaha ya da yı kullanarak olduğunu keşfetmem mi lazım!
                {
                    return true;
                }
            }

在你的清单文件中:

 <activity android:name=".PINSayfasi"
            android:process=":PIN"></activity>

所以主要的逻辑是打开和读取过程。


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