Notes: Android上檢測應(yīng)用是否被調(diào)到了后臺/前臺

前幾天在做一個密碼管理本類的應(yīng)用樊零,遇到這么一個需求:

應(yīng)用每次退出到后臺撤师,都要關(guān)閉存儲密碼信息的數(shù)據(jù)庫破花,并在應(yīng)用再切換到前臺時,向用戶展示一個輸入框讓用戶輸入訪問口令(該口令用于對數(shù)據(jù)庫進(jìn)行加解密)季研。

這就要求我對應(yīng)用的前后臺切換進(jìn)行監(jiān)聽。
為實現(xiàn)這個需求誉察,我第一個想到就是借助Activity生命周期各個回調(diào)方法來實現(xiàn)与涡。
大致思路就是在onPause()/onStop()方法中關(guān)閉數(shù)據(jù)庫,然后在onStart()/onResume()方法中檢查數(shù)據(jù)庫的狀態(tài)持偏,
然后根據(jù)這個狀態(tài)值的來做出對應(yīng)的動作驼卖。偽代碼表示如下:

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();
  }

}

興沖沖地按照這個思路實現(xiàn)了代碼,在虛擬機(jī)上測試鸿秆,很快就暴露了問題:
當(dāng)一個Activity啟動另外一個Activity酌畜,或者一個Activity從另外一個Activity返回時,都會調(diào)用相應(yīng)的onStart()onStop()方法卿叽。
因此這個方法僅僅適用于應(yīng)用只有單個Activity情況桥胞,當(dāng)有多個Activity時,上面的思路并不能夠達(dá)到需求考婴。

于是只能看看有沒有別的方法贩虾。例行g(shù)oogle了一下,發(fā)現(xiàn)stackoverflow上早已有人問過類似的問題沥阱。有兩個高票回答看起來都十分可行整胃。于是決定整理一下,當(dāng)作筆記。

1. 使用定時器TimerTask + Timer

第一個的思路跟我上面所述的方法十分地相似屁使,但是解決了上述方法中存在的問題在岂。
上述方法之所以不能工作,原因在于在onStop()方法中馬上就認(rèn)為應(yīng)用即將進(jìn)入后臺蛮寂,并且馬上關(guān)閉了數(shù)據(jù)庫蔽午。這樣就會對Activity間的切換進(jìn)行誤判。
而stackoverflow上的方案就是對時間進(jìn)行了一個判斷酬蹋。因為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()啟動一個定時任務(wù)骄恶,在MAX_ACTIVITY_TRANSITION_TIME_MS時間間隔之后才將應(yīng)用狀態(tài)設(shè)置為后臺狀態(tài)。
然后在onResume()方法中讀取應(yīng)用狀態(tài)匕垫,同時停止定時任務(wù)僧鲁,將應(yīng)用狀態(tài)設(shè)置為不在后臺。
這樣一來象泵,如果在onPause()方法調(diào)用后,超過MAX_ACTIVITY_TRANSITION_TIME_MS時間間隔才調(diào)用onResume()方法寞秃,則認(rèn)為應(yīng)用是從后臺切換到前臺的,否則就認(rèn)為是Activity間的切換偶惠。
具體的實現(xiàn)代碼在原帖里找到春寿。

2. 使用ComponentCallbacks2

這其實是一個非常直接有效的方法,也是我最終選擇的方法忽孽。從 Ice Cream Sandwich (API 14) 開始绑改,Android 官方便提供了這么一個回調(diào)接口。
ComponentCallbacks2繼承自ComponentCallbacks兄一,在ComponentCallbacks的 基礎(chǔ)上添加了onTrimMemory(int)回調(diào)厘线。
我們首先來看一下 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的主要作用就是在內(nèi)存狀態(tài)變化的時候通知應(yīng)用中的組件,讓應(yīng)用對其所占用的資源進(jìn)行適當(dāng)?shù)尼尫篷瑏斫档捅幌到y(tǒng)殺死的概率皆的。ComponentCallbacks2提供的回調(diào)適用于 Application 的各種組件。

onTrimMemory(int)回調(diào)中,系統(tǒng)提供給我們一個int型的Level值蹋盆,這個值代表著當(dāng)前系統(tǒng)可用內(nèi)存的狀態(tài)费薄。不同的值對應(yīng)不同的級別。
其中有一個值為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.

沒錯就是它栖雾,這個值代表了當(dāng)前應(yīng)用的UI已不再可見楞抡。通過它,我們就可以認(rèn)為應(yīng)用進(jìn)入了后臺析藕。
清楚了原理之后召廷,實現(xiàn)就變得非常簡單了。首先我們要寫一個實現(xiàn)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.
    }
}

當(dāng)然如果不想寫一個額外的類竞慢,使用匿名內(nèi)部類也是可以的先紫。
接著在應(yīng)用的 ApplicationonCreate()方法中注冊該回調(diào):

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

如果不再需要該回調(diào),可以通過unregisterComponentCallbacks(mMemoryBoss)來注銷它筹煮。不過一般不必要這么做遮精。

當(dāng)然,ComponentCallbacks2還提供了許多不同的Level值來指明內(nèi)存當(dāng)前的狀態(tài)败潦。有興趣可以去Android Developers查閱本冲。

參考鏈接:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市劫扒,隨后出現(xiàn)的幾起案子檬洞,更是在濱河造成了極大的恐慌,老刑警劉巖沟饥,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件添怔,死亡現(xiàn)場離奇詭異,居然都是意外死亡闷板,警方通過查閱死者的電腦和手機(jī)澎灸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門院塞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遮晚,“玉大人,你說我怎么就攤上這事拦止∠厍玻” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵汹族,是天一觀的道長萧求。 經(jīng)常有香客問我,道長顶瞒,這世上最難降的妖魔是什么夸政? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮榴徐,結(jié)果婚禮上守问,老公的妹妹穿的比我還像新娘。我一直安慰自己坑资,他們只是感情好耗帕,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著袱贮,像睡著了一般仿便。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天嗽仪,我揣著相機(jī)與錄音荒勇,去河邊找鬼。 笑死闻坚,一個胖子當(dāng)著我的面吹牛枕屉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鲤氢,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼搀擂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了卷玉?” 一聲冷哼從身側(cè)響起哨颂,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎相种,沒想到半個月后威恼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡寝并,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年箫措,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衬潦。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡斤蔓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镀岛,到底是詐尸還是另有隱情弦牡,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布漂羊,位于F島的核電站驾锰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏走越。R本人自食惡果不足惜椭豫,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望旨指。 院中可真熱鬧赏酥,春花似錦、人聲如沸淤毛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽低淡。三九已至姓言,卻和暖如春瞬项,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背何荚。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工囱淋, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人餐塘。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓妥衣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親戒傻。 傳聞我的和親對象是個殘疾皇子税手,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,515評論 25 707
  • 本篇文章是基于谷歌有關(guān)Graphic的一篇概覽文章的翻譯:http://source.android.com/de...
    lee_3do閱讀 7,099評論 2 21
  • afinalAfinal是一個android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,401評論 2 45
  • 1.把自己當(dāng)成boss ,現(xiàn)在有問題了需纳,你要怎么解決芦倒? 2.先做好自己的事,再去看看別人的事不翩,都要做兵扬,但是要有優(yōu)先...
    風(fēng)清楊閱讀 201評論 0 2
  • 大學(xué)遇到一個兄弟,還不是特熟口蝠。但我挺欣賞他的器钟,他學(xué)的計算機(jī),祝他一路成功妙蔗!我敢預(yù)言傲霸,十年之后,他會是這個學(xué)校的驕傲...