在一些場景中,常常會須要判斷App是否在後臺運行,好比是否顯示解鎖界面,收到新消息是否顯示Notification等。需求多是多樣化的,但所依仗的原理是相通的,今天Stay打算說說這些需求的最優解。面試
固然,Stay確定不會說去for loop判斷當前runningProcess或者runningTasks。好比:oop
這樣性能
或者這樣測試
這種方法調用起來感受就像是在用Windows系統裏的任務管理器,真是讓人蛋疼。咱們暫且不去計較性能問題,就說爲啥Android連個像樣的API都不給我,着實讓人鬱悶。spa
若是帶着這樣的質疑去調研,你會發現還真有其餘方式來實現。blog
Android在SDK 14的時候提供了一個Callback。ActivityLifecycleCallbacks,你能夠經過這個Callback拿到App全部Activity的生命週期回調。看圖:生命週期
這個Callback寫在Application裏的,你能夠在Application初始化的時候來註冊。咱們能夠寫個單例類來cache這些status。這裏我叫它AppStatusTracker。在Application的onCreate()裏讓AppStatusTracker註冊ActivityLifecycleCallbacks。ci
拿到這些Callback有什麼用呢,我怎麼能知道App是否在前臺運行呢。 element
別急,咱們先來講說Activity的生命週期。這是面試時必問題,雖然有官方答案,但真正理解生命週期,並靈活運用的很少。rem
咱們來設想下若是Activity調用了onResume(),那麼這個Activity確定是可見的,也就是運行在前臺的。若是調用了onPause(),且沒有Activity來調用onResume(),那麼App要跑到後臺去了。至於它是點了home鍵仍是back鍵我都無論。
經過這樣的判斷,咱們來利用ActivityLifecycleCallbacks回調的onActivityResumed()和onActivityPaused()方法來計數,若是隻有一個activityCount,那麼當前App在前臺,若是木有activityCount,它就在後臺。
好了,就這麼愉快的解決了,不再用for loop了。可是很快你會發現,這裏有個延時,會致使判斷不許確。
咱們假設有兩個Activities,一個A,一個B,從A跳轉到B,生命週期怎麼走的? A.onPause() -> B.onResume() 對應到ActivityLifecycleCallbacks裏是onActivityPaused(A) -> onActivityResumed(B),剛纔咱們說的計數resumeCount,在onActivityPaused()裏--,在onActivityResumed()裏++, 根據這樣的判斷會有個短暫的間隔,也就是在A的onPause()到B的onResume()之間,App是運行在後臺的,這樣邏輯確定就不對了。
那如何解決問題呢?若是你打印過生命週期的哪些方法,你會發現是Activity間切換的步驟是這樣的:
從WelcomeActivity跳轉到GestureActivity。(這裏只說onStart, onResume這些回調 )
A.onPause() -> B.onStart() -> B.onResume() -> A.onStop()
我估摸着60%的同窗都沒想過Activities之間切換的生命週期是什麼樣的。
經過這些回調咱們能夠將這個計數放在onStart()和onStop()中去,這樣就不會存在那個短暫間隔。activityCount==1,那麼就是前臺,activityCount==0,那就是後臺。這樣判斷很很簡單了吧。
如今再說,什麼狀況下來顯示手勢解鎖界面。
個人需求是當用戶鎖屏後再解鎖或者切換到後臺10分鐘後顯示手勢解鎖界面。
咱們拆分下需求,先說鎖屏,解鎖。
這個是有BroadCastReciever來接收的,註冊下就能夠了,每次收到鎖屏ACTION_SCREEN_OFF的action時,將AppStatusTracker裏的isScreenOff設置爲true。
當onActivityResumed()被調用時再將isScreenOff設爲false。
再說切換到後臺10分鐘後顯示手勢解鎖。這個只須要在onActivityStop()時更新下lastBackgroudTimestamp就能夠了
核心代碼以下:
原理很簡單,可是涉及到的知識點很重要,你們能夠本身寫寫測試下,別總依賴別人的代碼,別人的類庫,技術實現很簡單,但需求的變體擴展有時候仍是須要本身來想辦法解決的。