我们怎么判断一个app是处于前台后台,还是未启动状态,一般都会通过判断app的进程是否存活,如果进程存活说明是在后台或者前台,进程不存活,则说明app被杀死。
这里给一个工具类,判断应用是否已经启动
public class SystemUtils {
/**
* 判断应用是否已经启动
* @param context 一个context
* @param packageName 要判断应用的包名
* @return boolean
*/
public static boolean isAppAlive(Context context, String packageName){
ActivityManager activityManager =
(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> processInfos
= activityManager.getRunningAppProcesses();
for(int i = 0; i < processInfos.size(); i++){
if(processInfos.get(i).processName.equals(packageName)){
Log.i("NotificationLaunch",
String.format("the %s is running, isAppAlive return true", packageName));
return true;
}
}
Log.i("NotificationLaunch",
String.format("the %s is not running, isAppAlive return false", packageName));
return false;
}
之前在做友盟推送,想要实现的是如果app处于前台或者后台,那么就点开推送,直接跳转到想要的界面;如果app未启动,那么点开推送,就先启动app,再跳转到想要的界面。
并且友盟提供给了我们几个回调的方法
//1.每当有通知送达时,均会回调getNotification方法,因此可以通过监听此方法来判断通知是否送达。
UmengMessageHandler umengMessageHandler = new UmengMessageHandler() {
@Override
public Notification getNotification(Context context, UMessage uMessage) {
return super.getNotification(context, uMessage);
}
};
mPushAgent.setMessageHandler(umengMessageHandler);
第二个回调是自定义的通知打开动作,还有其他的,具体可以看友盟的官方文档。
//2.自定义通知打开动作,当用户点击了推送后,触发该回调
UmengNotificationClickHandler notificationClickHandler = new UmengNotificationClickHandler() {
@Override
public void dealWithCustomAction(Context context, UMessage msg) {
}
};
mPushAgent.setNotificationClickHandler(notificationClickHandler);
并且友盟的官方文档中也要求我们最好在application中注册,并重写它部分的回调方法,因为有些如果写在activity中,可能app会收不到推送,具体还是请看友盟的官方文档,写的还是很详细,清楚的。
当有消息推送到的时候,那么第一个回调就会触发,在该回调方法中,我可以通过发送广播,然后提醒某些界面更新UI,类似于未读信息的小红点显示。
当用户点击了推送后,第二个回调就会触发,一开始的时候,我是在回调方法中发送一个广播,然后在广播里先调用一开始的工具类判断app是否存活,然后再对其做相应的处理,但是当我打印log后,发现不管怎么样,打印出来的都是isAppAlive return true,一直是存活的,于是发现并不适用,除非你开一个service服务,一直在后台监听,然后通过静态注册的广播来通知,我是这么觉得的,因为我的广播是写在application中的dealWithCustomAction回调方法中的,当收到推送,点击推送通知时,其实友盟已经把应用在后台唤醒了,所以我每次打印的log都是isAppAlive return true。所以发现以上的方案只能pass掉了。
于是乎我从另一个角度入手——activity的任务栈。
1.当应用未启动时,那么该应用的任务栈为空,因为并没有任何的activity入栈。
2.当应用启动后,或者在后台,那么我们一个应用的栈底一般都是MainActivity,虽然启动都是从Splash开始,但是进到MainActivity就
finish掉了,所以启动应用后栈底通常都是MainActivity.
3.遍历任务栈,如果发现栈底是MainActivity,就说明应用在前台或者后台,否则应用未启动。
//通过activity的任务栈查找来判断app是否在前台
ActivityManager mAm = (ActivityManager) App.this.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> runningTasks = mAm.getRunningTasks(100);
for (ActivityManager.RunningTaskInfo runningTask : runningTasks) {
android.util.Log.e("run", runningTask.baseActivity.getClassName());
if (MAINACTTIVITY_CLASSNAME.equals(runningTask.baseActivity.getClassName())) {
isRun = true;
break;
}
}
并且我用了一个变量来记录应用是在前台还是后台,如果找到了就直接break出来,不用继续遍历了,如果不知道自己MainActivity的全类名,可以通过上面的log打印出来看看。