android监测程序进入后台以及从后台返回
来源:互联网 发布:能源消费总量 数据 编辑:程序博客网 时间:2024/05/26 05:52
最近项目需要监测android程序从后台返回的事件,百度了下,没有什么系统的总结,于是上StackOverFlow找到了个关于这个问题的讨论:How to detect when an Android app goes to the background and come back to the foreground。讨论过程中出现了几种都比较可行的方法,在此总结一下,供大家参考。
一、定时器方法
在按Home键的时候,Activity会调用onResume和onPause方法,重写这两个方法是一个基本入口。但是,在正常跳转的时候,Activity也会调用onResume和onPause方法,所以必须要对onResume和onPause的调用做一个判断,从而忽略掉正常跳转时的调用问题。那么怎么来实现这个判断呢?于是就有人想到了利用时间来判断:正常跳转过程中,从前一个Activity的onPause被调用,到新的Activity的onResume被调用,应该在一个很短的时间内就可以完成(除非你的Activity在onCreate中干了耗时操作);而进入桌面再从桌面返回的速度就会慢很多(需要人手动操作,相比跳转的毫秒级时间确实差距比较明显)。根据这个思路,就可以利用计时器去解决这个问题了。主要代码逻辑如下:
首先,你需要定义一个全局的Timer和TimerTask,确保在Activity之间可以共享,可以放在自定义Application中,也可以使用单例模式。Application示例如下:
首先,你需要定义一个全局的Timer和TimerTask,确保在Activity之间可以共享,可以放在自定义Application中,也可以使用单例模式。Application示例如下:
public class MyApplication extends Application { private Timer mActivityTransitionTimer; private TimerTask mActivityTransitionTimerTask; public boolean wasInBackground; // 阀值,可定义为一个可接受的时间(足够Activity跳转,来不及从桌面返回) private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000; public void startActivityTransitionTimer() { this.mActivityTransitionTimer = new Timer(); this.mActivityTransitionTimerTask = new TimerTask() { public void run() { MyApplication.this.wasInBackground = true; } }; this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask, MAX_ACTIVITY_TRANSITION_TIME_MS); } public void stopActivityTransitionTimer() { if (this.mActivityTransitionTimerTask != null) { this.mActivityTransitionTimerTask.cancel(); } if (this.mActivityTransitionTimer != null) { this.mActivityTransitionTimer.cancel(); } this.wasInBackground = false; }}然后,再你的BaseActivity中(我相信一个合格的开发人员都会定义这样一个Activity的基类),重写onResume和onPause方法:
@Overridepublic void onResume(){ super.onResume(); MyApplication myApp = (MyApplication)this.getApplication(); // 如果定时器已经结束了,wasInBackgroudn就会变成true,这个时候onResume就是从背景返回 if (myApp.wasInBackground){ //从背景返回了 } myApp.stopActivityTransitionTimer();}@Overridepublic void onPause(){ super.onPause(); // 启动定时器 ((MyApplication)this.getApplication()).startActivityTransitionTimer();}这个方法简单易懂,准确率通常也会比较高。不过也有不足的地方,比如没有办法监测进入背景的事件。同时,由于每次跳转都会开启一个计时器任务,存在一定程度上的内存浪费(不过基本可以忽略)。
二、onTrimMemory监听(API>=14)
在API14中,android提供了一个新的状态监听的接口 ComponentCallbacks2。在当中的onTrimMemory方法中,提供了一个状态参数 TRIM_MEMORY_UI_HIDDEN。官方文档对这个状态的解释如下:
“Level for onTrimMemory(int): the process had been showing a user interface, and is no longer doing so. Large allocations with the UI should be released at this point to allow memory to be better managed.” 该进程已经展示一个UI界面(onCreate完成?),并且停止了展示。UI中分配了的大块内存应该在这个时候被释放,以保证更佳的内存管理。
所以,这应该算是一个“正式”的进入后台标志了,之所以打引号,是因为这个状态本意上并不是为了监听进入后台而设计的,它只是为了让开发人员能够在程序进入后台的时候去释放一些内存。总而言之,这也是一种方法。
首先,你需要实现一个ComponentCallbacks2接口,并监听TRIM_MEMORY_UI_HIDDEN状态:
“Level for onTrimMemory(int): the process had been showing a user interface, and is no longer doing so. Large allocations with the UI should be released at this point to allow memory to be better managed.” 该进程已经展示一个UI界面(onCreate完成?),并且停止了展示。UI中分配了的大块内存应该在这个时候被释放,以保证更佳的内存管理。
所以,这应该算是一个“正式”的进入后台标志了,之所以打引号,是因为这个状态本意上并不是为了监听进入后台而设计的,它只是为了让开发人员能够在程序进入后台的时候去释放一些内存。总而言之,这也是一种方法。
首先,你需要实现一个ComponentCallbacks2接口,并监听TRIM_MEMORY_UI_HIDDEN状态:
public class MemoryBoss implements ComponentCallbacks2 { @Override public void onConfigurationChanged(final Configuration newConfig) { } @Override public void onLowMemory() { } @Override public void onTrimMemory(final int level) { if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // 进入后台 } // 如果有必要,你也可以进行一些清理内存操作 }}然后,在BaseActivity注册监听:
MemoryBoss mMemoryBoss;@Overridepublic void onCreate() { super.onCreate(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { mMemoryBoss = new MemoryBoss(); registerComponentCallbacks(mMemoryBoss); } }@Overridepublic void onDestroy(){ super.onDestroy(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { unregisterComponentCallbacks(mMemoryBoss); }}如果想要监听从后台返回的事件的话,在进入后台的时候设置个boolean值,然后在onResume时候进行判断即可。如果onResume的时候,程序已经进入后台,则可以判断是从后台返回的了。准确率是100%,但是只支持API14及之后。
三、计数方法
在Activity跳转的时候,总是先调用新Activity的onStart方法,然后再调用旧Activity的onStop方法。因此,可以利用这个逻辑,做一个Activity的计数效果,在onStart的时候加1,在onStop的时候减一。那么跳转的时候,因为是先加后减,所以值是恒大于0的。而进入后台的时候,先减后加,会出现等于0的效果。实现代码如下所示:
public abstract class BaseActivity extends Activity { private static int sessionDepth = 0; @Override protected void onStart() { super.onStart();if (sessionDepth == 0) { // 从后台返回} sessionDepth++; } @Override protected void onStop() { super.onStop(); if (sessionDepth > 0) sessionDepth--; if (sessionDepth == 0) { // 进入后台 } }}这个方法就显得比较优美了,代码逻辑简单,效果也不错。
四、利用onWindowFocusChanged的方法
// 用于判断是否从后台返回或者是否到后台 public static boolean isAppWentToBg = false; public static boolean isWindowFocused = false; public static boolean isBackPressed = false; @Override public void onBackPressed() { isBackPressed = true;super.onBackPressed(); } @Override protected void onStart() { if (isAppWentToBg) { isAppWentToBg = false; // 从后台返回 } super.onStart(); } @Override protected void onStop() { super.onStop(); if (!isWindowFocused) { isAppWentToBg = true; // 进入后台 } } @Override public void onWindowFocusChanged(boolean hasFocus) { isWindowFocused = hasFocus; if (isBackPressed && !hasFocus) { isBackPressed = false; isWindowFocused = true; } super.onWindowFocusChanged(hasFocus); }同样的,这个逻辑准确率也高。同时,它还加入了判断返回键的逻辑,更加人性化。
五、总结
onStart:Called when the activity is becoming visible to the user.当Activity可见时被调用
onStop:Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one. This may happen either because a new activity is being started, an existing one is being brought in front of this one, or this one is being destroyed.当Activity不可见时被调用,因为另一个Activity覆盖到了当前Activity上。这可能是由于一个新的Activity被启动了,一个已经存在的Activity被重新显示了,或者当前Activity被销毁了
因此,上述逻辑中的重写onResume和onPause操作都应当改为onStart和 onStop。上述的各种方法都是可用的,准确率也有保障,因此可以根据理解自行选择。
另外,在我自己实现这个逻辑的过程中,发现了这样一种现象。如果当前页面存在多个Activity的层级,从后台返回时会先调用第二个Activity的onStart,而不是栈顶的Activity。这可能是因为我设置了滑动返回的效果,即在栈顶Activity滑动过程中,之前的Activity会被显示出来。因此,必须保证两个Activity都是可见状态。这种情况下,想要在栈顶Activity实现返回弹出一个对话框的效果,如果直接按上述逻辑进行处理,则对话框会被显示在之前的Activity中,然后被新的Activity给覆盖掉。于是,我在监测到返回事件的时候,作了一个延迟操作,然后通过动态的获取栈顶Activity来弹出对话框,进而解决了这个问题。
总得来说,研究这个的过程还是十分的有趣,也让我一直以来对onStart和onStop的误解得到了修正。还是不得不吐槽一下,Google还是比百度强大很多。
0 0
- android监测程序进入后台以及从后台返回
- Android监测程序压入后台及从后台返回
- Android监测程序压入后台及从后台返回
- Android 从后台进入前台
- Android监听程序进入后台
- 内存紧张以及程序进入后台
- Android按返回键,程序进入后台运行,不关闭程序,finishAcrivity
- Android按返回键,程序进入后台运行,不关闭程序,finishAcrivity
- Android 程序进入后台 恢复到前台
- swift程序进入后台
- ios 程序进入后台并返回 调用的方法
- 返回键使程序后台,使用notification进入前台
- ios 程序进入后台并返回 调用的方法
- android按返回键和Home键都进入后台
- 程序进入后台运行NSTimer
- 【Swift】从前台进入后台,从后台进入前台
- Android 将程序从后台转到前台
- Android按下返回键后,程序不退出,进入后台运行。使用moveTaskToBack(boolean nonRoot)
- JavaScript总结(终极大总结)
- 如果有人问我GET和POST的区别...
- Junit-12
- 4. CSS id 选择器
- Python进阶之返回函数
- android监测程序进入后台以及从后台返回
- mysql create index
- mac 安装pillow模块
- C++ Primer Plus 学习笔记(第六章)
- 中天华易业务范围
- php设计模式之适配器模式
- WI-FI定位算法原理与介绍
- hal的调试基础
- OC语言__实现中等难度通讯录