原文地址:http://p.codekk.com/detail/Android/wenmingvs/AndroidProcessjava
提供6種方法來判斷App處於前臺仍是後臺,而且封裝成工具類供你們使用linux
最後一種方法堪稱Android黑科技(非原創),既能夠突破Android5.0以上的權限封鎖,獲取任意前臺App的包名,又不須要權限,歡迎你們star個人新項目android
2016.2.11更新------感謝@EffectiveMatrix大神帶來的新的判斷先後臺的方法github
傳入Context參數與想要判斷是否位於前臺的App的包名,會返回ture或者false表示App是否位於前臺安全
//六種方法任選其一 //使用方法一 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);
方法 | 判斷原理 | 須要權限 | 能夠判斷其餘應用位於前臺 | 特色 |
---|---|---|---|---|
方法一 | RunningTask | 否 | Android4.0系列能夠,5.0以上機器不行 | 5.0此方法被廢棄 |
方法二 | RunningProcess | 否 | 當App存在後臺常駐的Service時失效 | 無 |
方法三 | ActivityLifecycleCallbacks | 否 | 否 | 簡單有效,代碼最少 |
方法四 | UsageStatsManager | 是 | 是 | 須要用戶手動受權 |
方法五 | 經過Android無障礙功能實現 | 否 | 是 | 須要用戶手動受權 |
方法六 | 讀取/proc目錄下的信息 | 否 | 是 | 當proc目錄下文件夾過多時,過多的IO操做會引發耗時 |
原理
當一個App處於前臺的時候,會處於RunningTask的這個棧的棧頂,因此咱們能夠取出RunningTask的棧頂的任務進程,看他與咱們的想要判斷的App的包名是否相同,來達到效果服務器
缺點
getRunningTask方法在Android5.0以上已經被廢棄,只會返回本身和系統的一些不敏感的task,再也不返回其餘應用的task,用此方法來判斷自身App是否處於後臺,仍然是有效的,可是沒法判斷其餘應用是否位於前臺,由於再也不能獲取信息app
原理
經過runningProcess獲取到一個當前正在運行的進程的List,咱們遍歷這個List中的每個進程,判斷這個進程的一個importance 屬性是不是前臺進程,而且包名是否與咱們判斷的APP的包名同樣,若是這兩個條件都符合,那麼這個App就處於前臺ide
缺點:
在聊天類型的App中,經常須要常駐後臺來不間斷的獲取服務器的消息,這就須要咱們把Service設置成START_STICKY,kill 後會被重啓(等待5秒左右)來保證Service常駐後臺。若是Service設置了這個屬性,這個App的進程就會被判斷是前臺,代碼上的表現就是appProcess.importance的值永遠是 ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND,這樣就永遠沒法判斷出到底哪一個是前臺了。工具
原理
AndroidSDK14在Application類裏增長了ActivityLifecycleCallbacks,咱們能夠經過這個Callback拿到App全部Activity的生命週期回調。
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); }
知道這些信息,咱們就能夠用更官方的辦法來解決問題,固然仍是利用方案二里的Activity生命週期的特性,咱們只須要在Application的onCreate()裏去註冊上述接口,而後由Activity回調回來運行狀態便可。
可能還有人在糾結,我用back鍵切到後臺和用Home鍵切到後臺,同樣嗎?以上方法適用嗎?在Android應用開發中通常認爲back鍵是能夠捕獲的,而Home鍵是不能捕獲的(除非修改framework),可是上述方法從Activity生命週期着手解決問題,雖然這兩種方式的Activity生命週期並不相同,可是兩者都會執行onStop();因此並不關心究竟是觸發了哪一個鍵切入後臺的。另外,Application是否被銷燬,都不會影響判斷的正確性
原理
經過使用UsageStatsManager獲取,此方法是Android5.0以後提供的新API,能夠獲取一個時間段內的應用統計信息,可是必須知足一下要求
使用前提
<uses-permission xmlns:tools="http://schemas.android.com/tools" android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
很是感謝@EffectiveMatrix大神帶來的新的判斷先後臺的方法
此方法屬於他原創,具體的博文參照這裏http://effmx.com/articles/tong-guo-android-fu-zhu-gong-neng-accessibility-service-jian-ce-ren-yi-qian-tai-jie-mian/
此方法沒法直觀的經過下拉通知視圖來進行先後臺的觀察,請到LogCat中進行觀察便可,如下是LogCat中打印的信息
原理
Android 輔助功能(AccessibilityService) 爲咱們提供了一系列的事件回調,幫助咱們指示一些用戶界面的狀態變化。 咱們能夠派生輔助功能類,進而對不一樣的 AccessibilityEvent 進行處理。 一樣的,這個服務就能夠用來判斷當前的前臺應用
優點
劣勢
此方法並不是我原創,原做者是國外的大神,GitHub項目在這裏,https://github.com/jaredrummler/AndroidProcesses,也一併加入到工程中,供你們作全面的參考選擇
原理
無心中看到烏雲上有人提的一個漏洞,Linux系統內核會把process進程信息保存在/proc目錄下,Shell命令去獲取的他,再根據進程的屬性判斷是否爲前臺
優勢
缺點
用法
獲取一系列正在運行的App的進程
List<AndroidAppProcess> processes = ProcessManager.getRunningAppProcesses();
獲取任一正在運行的App進程的詳細信息
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();
判斷是否在前臺
if (ProcessManager.isMyProcessInTheForeground()) { // do stuff }
獲取一系列正在運行的App進程的詳細信息
List<ActivityManager.RunningAppProcessInfo> processes = ProcessManager.getRunningAppProcessInfo(ctx);