在我們開發的過程中,經常會遇到需要我們判斷app進入后台,或者切換到前台的情況。比如我們想判斷app切換到前台時,顯示一個解鎖界面,要求用戶輸入解鎖密碼才能繼續進行操作;我們想判斷app切換到后台,記錄一下log;或者當用戶切換回前台時,我們想刷新一下頁面的數據等等......
android里面監聽app前后台的方案很多(這還是得歸根於安卓提供了豐富的api和強大的架構支撐,呵呵~),比如可以通過ActivityManager提供的getRunningAppProcesses()獲取系統當前運行的app,從而判斷app是否處於前台。或者通過監聽點擊Home鍵,判斷app是否回到了后台。下面將針對筆者已知的幾種方案,進行對比分析。
方案一:利用ActivityManager的RunningAppProcessInfo類
ActivityManager在整個系統里面起着非常重要的作用,主要為系統中運行着的activity交互提供接口,其中RunningAppProcessInfo類則封裝了正在運行着的進程信息,當然也包含了正在運行的app的包名,因此我們可以activitymanager.getRunningAppProcesses()獲取當前運行的app列表,對比自身的包名,來判斷本身app是否處於前台運行。
這打斷一下,ActivityManager框架是Android系統十分重要的一部分,在以后有時間,筆者會好好學習整理ActivityManager框架的分析。
回到這里,下面給出部分關鍵代碼。
/** * App前后台狀態 */ public boolean isForeground = false; @Override protected void onResume() { ...... if (isForeground == false) { //由后台切換到前台 isForeground = true; } } @Override protected void onPause() { ...... if (!isAppOnForeground()) { //由前台切換到后台 isForeground = false; } } /** * 判斷app是否處於前台 * * @return */ public boolean isAppOnForeground() { ActivityManager activityManager = (ActivityManager) getApplicationContext() .getSystemService(Context.ACTIVITY_SERVICE); String packageName = getApplicationContext().getPackageName(); /** * 獲取Android設備中所有正在運行的App */ List<RunningAppProcessInfo> appProcesses = activityManager .getRunningAppProcesses(); if (appProcesses == null) return false; for (RunningAppProcessInfo appProcess : appProcesses) { // The name of the process that this object is associated with. if (appProcess.processName.equals(packageName) && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { return true; } } return false; }
小結:通過ActivityManager來獲取當前運行的app列表,然后判斷我們的app是否處於前台,能基本達到我們的預期需求。但如果將上面代碼放到每一個activity,或者activity基類里面,這消耗還是挺大的。而且而且,ActivityManager通過.getRunningAppProcesses()獲取當前運行列表這個方法,在5.0以后已經被deprecated掉了....(心中萬馬奔騰...)
方案二:監聽Home鍵點擊
說起home鍵的監聽,也算是android里面的一個梗。這看上去簡單的功能,實際上實現起來卻十分的曲折,這跟android系統的設計有很大的關系。當home鍵被點擊的時候,會發出一個系統廣播,在系統收到這個廣播以后,會在framework層做一系列操作將當前的app退到后台,然后把事件消費掉不傳給應用層,所以這時候 onKeyDown事件也接收不到了..用官方的解釋就是——“Home key. This key is handled by the framework and is never delivered to applications.”。實際上這也是為了安全性的考慮,不然每家的app都監聽home鍵,然后禁掉響應,不都成了流氓軟件了。
官方不支持,可是這難不到我們萬能的攻城獅們的,畢竟有很多想我們正規的開發者,還是需要監聽home鍵來做一些如寫日志之類的操作的。網上谷歌百度會有很多類似的解決方案,在這里就不展開了。(不過這里可以推薦一下)
小結:我們能監聽到home鍵點擊,當然就知道app處於前台還是后台了。但畢竟這個方案是基於官方不支持的前提下的,而且home鍵的監聽在很多設備都會有兼容性的問題,因此我們不大推薦這樣做。
方案三:利用ActivityLifecycleCallbacks監聽所有activity的生命周期
通過監聽所有activity的onStart、onStop調用,然后統計當前是不是所有的activity都調用了onStop,確實可以判斷app處於了后台,不過讓我們重寫每一個activity的onStop,並加這段奇怪的代碼,實在不大優雅,即使在activity基類里面統一寫,那天如果忘了或者不需要繼承基類的activity,就不大好了。
因此,這里推薦一個新的接口ActivityLifecycleCallbacks,說新也不新,其實早在API 14 (android 4.0)就已經推出了。ActivityLifecycleCallbacks接口在Application類里面,因此需要我們自己繼承Application,自定義一個MyApplication,然后注冊接口。ActivityLifecycleCallbacks為application提供了對所有activity生命周期的監聽,因此我們通過重寫ActivityLifecycleCallbacks的onActivityStarted和onActivityStopped方法,定義一個變量,來統計當前有幾個activity處於前台。
/** * 當前Acitity個數 */ private int activityAount = 0; @Override public void onCreate() { ...... registerActivityLifecycleCallbacks(activityLifecycleCallbacks); ...... } /** * Activity 生命周期監聽,用於監控app前后台狀態切換 */ ActivityLifecycleCallbacks activityLifecycleCallbacks = new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { } @Override public void onActivityStarted(Activity activity) { // if (activityAount == 0) { // //app回到前台 // isForeground = true; // } activityAount++; } @Override public void onActivityResumed(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { activityAount--; if (activityAount == 0) { isForeground = false; } } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityDestroyed(Activity activity) { } };
以上代碼寫在MyApplication里面。怎么樣,是不是很簡單快捷!而且准確無誤。
總結:
1、利用ActivityManager的RunningAppProcessInfo類,直接粗暴,官方摒棄,不推薦;
2、監聽Home鍵點擊,官方不支持,兼容性差,不穩定,不推薦;
3、利用ActivityLifecycleCallbacks監聽所有activity的生命周期,官方指定飲品,哦,不對,官方指定接口,大力推薦!我們舉一反三,利用ActivityLifecycleCallbacks監聽,我們還能控制我們的activity堆棧,甚至還可以在里面做日志統計...想想還是很強大的。
PS:雖則利用ActivityLifecycleCallbacks接口監聽的方案最優,但這畢竟是4.0以后的產品,因此對於4.0以下的,可以考慮增加方案一判斷。