Android 判斷應(yīng)用是否在前臺(tái)

本文轉(zhuǎn)轉(zhuǎn)自GitHub https://github.com/wenmingvs/AndroidProcess


AndroidProcess

提供6種方法來(lái)判斷App處于前臺(tái)還是后臺(tái),并且封裝成工具類(lèi)供大家使用

最后一種方法堪稱(chēng)Android黑科技(非原創(chuàng)),既可以突破Android5.0以上的權(quán)限封鎖,獲取任意前臺(tái)App的包名,又不需要權(quán)限,此方法并非我原創(chuàng),原作者是國(guó)外的大神,GitHub項(xiàng)目在這里,也一并加入到工程中,供大家做全面的參考選擇

2016.2.11更新------感謝@EffectiveMatrix大神帶來(lái)的新的判斷前后臺(tái)的方法

快速下載體驗(yàn)

百度網(wǎng)盤(pán)

預(yù)覽圖

enter image description here

用法

傳入Context參數(shù)與想要判斷是否位于前臺(tái)的App的包名,會(huì)返回ture或者false表示App是否位于前臺(tái)


//六種方法任選其一

//使用方法一
Boolean isForeground = BackgroundUtil.getRunningTask(context, packageName);
//使用方法二
Boolean isForeground = BackgroundUtil.getRunningAppProcesses(context, packageName);
//使用方法三
Boolean isForeground = BackgroundUtil.getApplicationValue(context);
//使用方法四
Boolean isForeground = BackgroundUtil.queryUsageStats(context, packageName);
//使用方法五
Boolean isForeground = BackgroundUtil.getFromAccessibilityService(context, packageName);
//使用方法六
Boolean isForeground = BackgroundUtil.getLinuxCoreInfo(context, packageName);

六種方法的區(qū)別

方法 判斷原理 需要權(quán)限 可以判斷其他應(yīng)用位于前臺(tái) 特點(diǎn)
方法一 RunningTask Android4.0系列可以,5.0以上機(jī)器不行 5.0此方法被廢棄
方法二 RunningProcess 當(dāng)App存在后臺(tái)常駐的Service時(shí)失效 無(wú)
方法三 ActivityLifecycleCallbacks 簡(jiǎn)單有效,代碼最少
方法四 UsageStatsManager 需要用戶手動(dòng)授權(quán)
方法五 通過(guò)Android無(wú)障礙功能實(shí)現(xiàn) 需要用戶手動(dòng)授權(quán)
方法六 讀取/proc目錄下的信息 當(dāng)proc目錄下文件夾過(guò)多時(shí),過(guò)多的IO操作會(huì)引起耗時(shí)

方法一:通過(guò)RunningTask

enter image description here

原理
當(dāng)一個(gè)App處于前臺(tái)的時(shí)候,會(huì)處于RunningTask的這個(gè)棧的棧頂,所以我們可以取出RunningTask的棧頂?shù)娜蝿?wù)進(jìn)程,看他與我們的想要判斷的App的包名是否相同,來(lái)達(dá)到效果

缺點(diǎn)
getRunningTask方法在Android5.0以上已經(jīng)被廢棄,只會(huì)返回自己和系統(tǒng)的一些不敏感的task,不再返回其他應(yīng)用的task,用此方法來(lái)判斷自身App是否處于后臺(tái),仍然是有效的,但是無(wú)法判斷其他應(yīng)用是否位于前臺(tái),因?yàn)椴辉倌塬@取信息

方法二:通過(guò)RunningProcess

enter image description here

原理
通過(guò)runningProcess獲取到一個(gè)當(dāng)前正在運(yùn)行的進(jìn)程的List,我們遍歷這個(gè)List中的每一個(gè)進(jìn)程,判斷這個(gè)進(jìn)程的一個(gè)importance 屬性是否是前臺(tái)進(jìn)程,并且包名是否與我們判斷的APP的包名一樣,如果這兩個(gè)條件都符合,那么這個(gè)App就處于前臺(tái)

缺點(diǎn)
在聊天類(lèi)型的App中,常常需要常駐后臺(tái)來(lái)不間斷的獲取服務(wù)器的消息,這就需要我們把Service設(shè)置成START_STICKY,kill 后會(huì)被重啟(等待5秒左右)來(lái)保證Service常駐后臺(tái)。如果Service設(shè)置了這個(gè)屬性,這個(gè)App的進(jìn)程就會(huì)被判斷是前臺(tái),代碼上的表現(xiàn)就是appProcess.importance的值永遠(yuǎn)是 ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND,這樣就永遠(yuǎn)無(wú)法判斷出到底哪個(gè)是前臺(tái)了。

方法三:通過(guò)ActivityLifecycleCallbacks

enter image description here

原理
AndroidSDK14在Application類(lèi)里增加了ActivityLifecycleCallbacks,我們可以通過(guò)這個(gè)Callback拿到App所有Activity的生命周期回調(diào)。

 public interface ActivityLifecycleCallbacks {
        void onActivityCreated(Activity activity, Bundle savedInstanceState);
        void onActivityStarted(Activity activity);
        void onActivityResumed(Activity activity);
        void onActivityPaused(Activity activity);
        void onActivityStopped(Activity activity);
        void onActivitySaveInstanceState(Activity activity, Bundle outState);
        void onActivityDestroyed(Activity activity);
    }

知道這些信息,我們就可以用更官方的辦法來(lái)解決問(wèn)題,當(dāng)然還是利用方案二里的Activity生命周期的特性,我們只需要在Application的onCreate()里去注冊(cè)上述接口,然后由Activity回調(diào)回來(lái)運(yùn)行狀態(tài)即可。

可能還有人在糾結(jié),我用back鍵切到后臺(tái)和用Home鍵切到后臺(tái),一樣嗎?以上方法適用嗎?在Android應(yīng)用開(kāi)發(fā)中一般認(rèn)為back鍵是可以捕獲的,而Home鍵是不能捕獲的(除非修改framework),但是上述方法從Activity生命周期著手解決問(wèn)題,雖然這兩種方式的Activity生命周期并不相同,但是二者都會(huì)執(zhí)行onStop();所以并不關(guān)心到底是觸發(fā)了哪個(gè)鍵切入后臺(tái)的。另外,Application是否被銷(xiāo)毀,都不會(huì)影響判斷的正確性

方法四:通過(guò)使用UsageStatsManager獲取

enter image description here

原理
通過(guò)使用UsageStatsManager獲取,此方法是Android5.0之后提供的新API,可以獲取一個(gè)時(shí)間段內(nèi)的應(yīng)用統(tǒng)計(jì)信息,但是必須滿足一下要求

使用前提

  1. 此方法只在android5.0以上有效
  2. AndroidManifest中加入此權(quán)限
<uses-permission  android:name="android.permission.PACKAGE_USAGE_STATS" />
  1. 打開(kāi)手機(jī)設(shè)置,點(diǎn)擊安全-高級(jí),在有權(quán)查看使用情況的應(yīng)用中,為這個(gè)App打上勾
enter image description here
enter image description here

方法五:通過(guò)Android自帶的無(wú)障礙功能

非常感謝@EffectiveMatrix大神帶來(lái)的新的判斷前后臺(tái)的方法

此方法屬于他原創(chuàng),具體的博文參照這里http://effmx.com/articles/tong-guo-android-fu-zhu-gong-neng-accessibility-service-jian-ce-ren-yi-qian-tai-jie-mian/

此方法無(wú)法直觀的通過(guò)下拉通知視圖來(lái)進(jìn)行前后臺(tái)的觀察,請(qǐng)到LogCat中進(jìn)行觀察即可,以下是LogCat中打印的信息

enter image description here

原理
Android 輔助功能(AccessibilityService) 為我們提供了一系列的事件回調(diào),幫助我們指示一些用戶界面的狀態(tài)變化。 我們可以派生輔助功能類(lèi),進(jìn)而對(duì)不同的 AccessibilityEvent 進(jìn)行處理。 同樣的,這個(gè)服務(wù)就可以用來(lái)判斷當(dāng)前的前臺(tái)應(yīng)用

優(yōu)勢(shì)

  1. AccessibilityService 有非常廣泛的 ROM 覆蓋,特別是非國(guó)產(chǎn)手機(jī),從 Android API Level 8(Android 2.2) 到 Android Api Level 23(Android 6.0)
  2. AccessibilityService 不再需要輪詢的判斷當(dāng)前的應(yīng)用是不是在前臺(tái),系統(tǒng)會(huì)在窗口狀態(tài)發(fā)生變化的時(shí)候主動(dòng)回調(diào),耗時(shí)和資源消耗都極小
  3. 不需要權(quán)限請(qǐng)求
  4. 它是一個(gè)穩(wěn)定的方法,與 “方法6”讀取 /proc 目錄不同,它并非利用 Android 一些設(shè)計(jì)上的漏洞,可以長(zhǎng)期使用的可能很大
  5. 可以用來(lái)判斷任意應(yīng)用甚至 Activity, PopupWindow, Dialog 對(duì)象是否處于前臺(tái)

劣勢(shì)

  1. 需要要用戶開(kāi)啟輔助功能
  2. 輔助功能會(huì)伴隨應(yīng)用被“強(qiáng)行停止”而剝奪

方法六:讀取Linux系統(tǒng)內(nèi)核保存在/proc目錄下的process進(jìn)程信息

enter image description here

此方法并非我原創(chuàng),原作者是國(guó)外的大神,GitHub項(xiàng)目在這里,也一并加入到工程中,供大家做全面的參考選擇

原理
無(wú)意中看到烏云上有人提的一個(gè)漏洞,Linux系統(tǒng)內(nèi)核會(huì)把process進(jìn)程信息保存在/proc目錄下,Shell命令去獲取的他,再根據(jù)進(jìn)程的屬性判斷是否為前臺(tái)

優(yōu)點(diǎn)

  1. 不需要任何權(quán)限
  2. 可以判斷任意一個(gè)應(yīng)用是否在前臺(tái),而不局限在自身應(yīng)用

缺點(diǎn)

  1. 當(dāng)/proc下文件夾過(guò)多時(shí),此方法是耗時(shí)操作

用法
獲取一系列正在運(yùn)行的App的進(jìn)程

List<AndroidAppProcess> processes = ProcessManager.getRunningAppProcesses();

獲取任一正在運(yùn)行的App進(jìn)程的詳細(xì)信息

AndroidAppProcess process = processes.get(location);
String processName = process.name;

Stat stat = process.stat();
int pid = stat.getPid();
int parentProcessId = stat.ppid();
long startTime = stat.stime();
int policy = stat.policy();
char state = stat.state();

Statm statm = process.statm();
long totalSizeOfProcess = statm.getSize();
long residentSetSize = statm.getResidentSetSize();

PackageInfo packageInfo = process.getPackageInfo(context, 0);
String appName = packageInfo.applicationInfo.loadLabel(pm).toString();

判斷是否在前臺(tái)

if (ProcessManager.isMyProcessInTheForeground()) {
  // do stuff
}

獲取一系列正在運(yùn)行的App進(jìn)程的詳細(xì)信息

List<ActivityManager.RunningAppProcessInfo> processes = ProcessManager.getRunningAppProcessInfo(ctx);

Gradle 構(gòu)建

  • 版本
    • 最新 Android SDK
    • 最新 Gradle
  • 環(huán)境變量
    • ANDROID_HOME
    • GRADLE_HOME,同時(shí)把bin放入path變量
    • Android SDK 安裝,都更新到最新
    • Android SDK Build-tools更新到最新
    • Google Repository更新到最新
    • Android Support Repository更新到最新
    • Android Support Library更新到最新

相信未來(lái)

當(dāng)蜘蛛網(wǎng)無(wú)情地查封了我的爐臺(tái)
當(dāng)灰燼的余煙嘆息著貧困的悲哀
我依然固執(zhí)地鋪平失望的灰燼
用美麗的雪花寫(xiě)下:相信未來(lái)

當(dāng)我的紫葡萄化為深秋的露水
當(dāng)我的鮮花依偎在別人的情懷
我依然固執(zhí)地用凝霜的枯藤
在凄涼的大地上寫(xiě)下:相信未來(lái)

我要用手指那涌向天邊的排浪
我要用手掌那托住太陽(yáng)的大海
搖曳著曙光那枝溫暖漂亮的筆桿
用孩子的筆體寫(xiě)下:相信未來(lái)

我之所以堅(jiān)定地相信未來(lái)
是我相信未來(lái)人們的眼睛
她有撥開(kāi)歷史風(fēng)塵的睫毛
她有看透歲月篇章的瞳孔

不管人們對(duì)于我們腐爛的皮肉
那些迷途的惆悵、失敗的苦痛
是寄予感動(dòng)的熱淚、深切的同情
還是給以輕蔑的微笑、辛辣的嘲諷

我堅(jiān)信人們對(duì)于我們的脊骨
那無(wú)數(shù)次的探索、迷途、失敗和成功
一定會(huì)給予熱情、客觀、公正的評(píng)定
是的,我焦急地等待著他們的評(píng)定

朋友,堅(jiān)定地相信未來(lái)吧
相信不屈不撓的努力
相信戰(zhàn)勝死亡的年輕
相信未來(lái)、熱愛(ài)生命

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,038評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,853評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,616評(píng)論 6 408
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,112評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,355評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,727評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,928評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,165評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,570評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,813評(píng)論 1 282
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,585評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,892評(píng)論 2 372

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