Notes: Android上检测应用是否被调到了后台/前台

前几天在做一个密码管理本类的应用,遇到这么一个需求:

应用每次退出到后台,都要关闭存储密码信息的数据库,并在应用再切换到前台时,向用户展示一个输入框让用户输入访问口令(该口令用于对数据库进行加解密)。

这就要求我对应用的前后台切换进行监听。
为实现这个需求,我第一个想到就是借助Activity生命周期各个回调方法来实现。
大致思路就是在onPause()/onStop()方法中关闭数据库,然后在onStart()/onResume()方法中检查数据库的状态,
然后根据这个状态值的来做出对应的动作。伪代码表示如下:

public class BaseActivity extends AppCompatActivity {

  @Override
  protected void onStart() {
      super.onStart();
      if(isSecureDataBaseClosed()){
          showEnterPasswordActivity();
      }else{
          //do something else here
      }
  }

  @Override
  protected void onStop() {
      super.onStop();
      closeSecureDatabase();
  }

}

兴冲冲地按照这个思路实现了代码,在虚拟机上测试,很快就暴露了问题:
当一个Activity启动另外一个Activity,或者一个Activity从另外一个Activity返回时,都会调用相应的onStart()onStop()方法。
因此这个方法仅仅适用于应用只有单个Activity情况,当有多个Activity时,上面的思路并不能够达到需求。

于是只能看看有没有别的方法。例行google了一下,发现stackoverflow上早已有人问过类似的问题。有两个高票回答看起来都十分可行。于是决定整理一下,当作笔记。

1. 使用定时器TimerTask + Timer

第一个的思路跟我上面所述的方法十分地相似,但是解决了上述方法中存在的问题。
上述方法之所以不能工作,原因在于在onStop()方法中马上就认为应用即将进入后台,并且马上关闭了数据库。这样就会对Activity间的切换进行误判。
而stackoverflow上的方案就是对时间进行了一个判断。因为Activity间的一次切换时间是比较短的,因此可以借助这一点来改良上述方案。
下面给出描述这个思路的伪代码:

private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;

@Override
public void onResume(){
    super.onResume();
    if(wasAppInBackground()){
        //Do specific came-here-from-background code
    }
    stopTimer();
    setAppWasInBackground(false);
}

@Override
public void onPause(){
    super.onPause();
    startTimer(MAX_ACTIVITY_TRANSITION_TIME_MS,TaskToSetAppWasInBackground(true));
}

简单概括这个方法,就是在onPause()启动一个定时任务,在MAX_ACTIVITY_TRANSITION_TIME_MS时间间隔之后才将应用状态设置为后台状态。
然后在onResume()方法中读取应用状态,同时停止定时任务,将应用状态设置为不在后台。
这样一来,如果在onPause()方法调用后,超过MAX_ACTIVITY_TRANSITION_TIME_MS时间间隔才调用onResume()方法,则认为应用是从后台切换到前台的,否则就认为是Activity间的切换。
具体的实现代码在原帖里找到。

2. 使用ComponentCallbacks2

这其实是一个非常直接有效的方法,也是我最终选择的方法。从 Ice Cream Sandwich (API 14) 开始,Android 官方便提供了这么一个回调接口。
ComponentCallbacks2继承自ComponentCallbacks,在ComponentCallbacks的 基础上添加了onTrimMemory(int)回调。
我们首先来看一下 Android Developers 上对ComponentCallbacks2的说明:

Extended ComponentCallbacks interface with a new callback for finer-grained memory management. This interface is available in all application components (Activity, Service, ContentProvider, and Application).

You should implement onTrimMemory(int) to incrementally release memory based on current system constraints. Using this callback to release your resources helps provide a more responsive system overall, but also directly benefits the user experience for your app by allowing the system to keep your process alive longer. That is, if you don't trim your resources based on memory levels defined by this callback, the system is more likely to kill your process while it is cached in the least-recently used (LRU) list, thus requiring your app to restart and restore all state when the user returns to it.

可见ComponentCallbacks2的主要作用就是在内存状态变化的时候通知应用中的组件,让应用对其所占用的资源进行适当的释放,来降低被系统杀死的概率。ComponentCallbacks2提供的回调适用于 Application 的各种组件。

onTrimMemory(int)回调中,系统提供给我们一个int型的Level值,这个值代表着当前系统可用内存的状态。不同的值对应不同的级别。
其中有一个值为TRIM_MEMORY_UI_HIDDEN,对这个level值的定义如下:

Your app's UI is no longer visible, so this is a good time to release large resources that are used only by your UI.

没错就是它,这个值代表了当前应用的UI已不再可见。通过它,我们就可以认为应用进入了后台。
清楚了原理之后,实现就变得非常简单了。首先我们要写一个实现ComponentCallbacks2的类,比如这里命名为MemoryBoss:

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) {
            // We're in the Background
        }
        // you might as well implement some memory cleanup here and be a nice Android dev.
    }
}

当然如果不想写一个额外的类,使用匿名内部类也是可以的。
接着在应用的 ApplicationonCreate()方法中注册该回调:

MemoryBoss mMemoryBoss;
@Override
public void onCreate() {
   super.onCreate();
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
      mMemoryBoss = new MemoryBoss();
      registerComponentCallbacks(mMemoryBoss);
   } 
}

如果不再需要该回调,可以通过unregisterComponentCallbacks(mMemoryBoss)来注销它。不过一般不必要这么做。

当然,ComponentCallbacks2还提供了许多不同的Level值来指明内存当前的状态。有兴趣可以去Android Developers查阅。

参考链接:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,635评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,543评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,083评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,640评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,640评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,262评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,833评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,736评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,280评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,369评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,503评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,870评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,340评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,460评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,909评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,512评论 2 359

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,283评论 25 707
  • 本篇文章是基于谷歌有关Graphic的一篇概览文章的翻译:http://source.android.com/de...
    lee_3do阅读 7,139评论 2 21
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,436评论 2 45
  • 1.把自己当成boss ,现在有问题了,你要怎么解决? 2.先做好自己的事,再去看看别人的事,都要做,但是要有优先...
    风清杨阅读 208评论 0 2
  • 大学遇到一个兄弟,还不是特熟。但我挺欣赏他的,他学的计算机,祝他一路成功!我敢预言,十年之后,他会是这个学校的骄傲...