Android中的前臺就是指用戶可見哗蜈,后臺就是指用戶不可見前标。
對于Activity來說坠韩,可以通過生命周期,監(jiān)聽回到前臺炼列,或切到后臺的行為只搁。
但是對于Application來說,就很難監(jiān)控回到前臺還是切到后臺俭尖,因為Android任務(wù)棧的設(shè)計中氢惋,允許來自多個Application的Activity組成任務(wù)棧,所以無法通過Activity的生命周期稽犁,直接監(jiān)聽Application在前后臺的切換焰望。
針對Application在前后臺切換的監(jiān)聽,一般有兩種思路:
- RunningAppProcessInfo
用RunningAppProcessInfo信息已亥,通過appProcess.processName和App的packageName對比熊赖,找到App所在的進程,通過進程的優(yōu)先級判斷是否是前臺進程虑椎。
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;
}
}
- 統(tǒng)計Activity的生命周期
在Application中監(jiān)聽所有Activity的生命周期震鹉,通過統(tǒng)計活動Activity的數(shù)量進行判斷(代碼略)。
這兩種思路绣檬,其實都依賴Activity的生命周期足陨,需要在onStop中進行檢查嫂粟,在很多場景中也是好用的娇未。
但是,Activity并不總會執(zhí)行onStop星虹,如果打開的新Activity是透明背景零抬,或者是彈出框格式,舊Activity不會被遮擋宽涌,就不會執(zhí)行onStop平夜,對應(yīng)的也沒有onStart,如果這個新的Activity屬于其他Application卸亮,就無法監(jiān)聽到Application的前后臺切換了忽妒。
為了解決這個問題,我們基于第2個思路兼贸,進行了擴展段直,通過對整個生命周期的判斷,實現(xiàn)在onResume中溶诞,監(jiān)聽Application回到前臺的功能鸯檬。(目前還沒有辦法判斷退到后臺)
主要思路如下:
·在常規(guī)情況下,包括Home鍵返回桌面的情況下螺垢,思路2是好用的喧务。
·在舊Activity不被遮擋赖歌、不執(zhí)行onStop的情況下,滿足以下三個過濾條件的功茴,視為Application回到前臺:
1.執(zhí)行過onPause(說明有其他Activity遮蓋)
2.沒有在onStart中判定為回到前臺(避免在常規(guī)情況下庐冯,事件重復(fù))
3.不是第一次onResume(如果本App打開了新的Activity,也會先執(zhí)行一遍onPause坎穿,那么在Application級別肄扎,第一次進入onResume會被錯誤觸發(fā),導(dǎo)致判斷失靈赁酝,所以還需要判斷已經(jīng)執(zhí)行過至少一次onResume)
第三條跟兩個Activity的生命周期有關(guān)犯祠,其判斷邏輯如圖:
經(jīng)測試,該方法能有效監(jiān)聽Application回到前臺的事件酌呆。
我們把這個邏輯抽象為一個工具類衡载,代碼如下:
public class OnFrontUtil {
private static final String TAG="OnFrontUtil";
boolean isResumed = false;
boolean isPaused = false;
boolean isFront = false;
int count=0;
//因為需要統(tǒng)計Activity,所以用單例實現(xiàn)
private volatile static OnFrontUtil instance;
private OnFrontUtil(Application app, OnFrontCallback callback){
registerOnFront(app,callback);
}
//只需要在初始化時被調(diào)用一次隙袁,所以修改了單例寫法痰娱,不再返回實例,只完成注冊監(jiān)聽
public static void listenOnFront(Application app,OnFrontCallback callback){
if(instance==null){
synchronized (OnFrontUtil.class){
if(instance==null){
instance=new OnFrontUtil(app,callback);
}
}
}
}
//向調(diào)用者反饋回到前臺事件
public interface OnFrontCallback{
void onFront();
}
//通過監(jiān)聽和統(tǒng)計Activity生命周期菩收,判斷App是否來到前臺顯示
private void registerOnFront(Application app,final OnFrontCallback callback){
app.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
isResumed = false;
}
@Override
public void onActivityStarted(Activity activity) {
count++;
Log.i(TAG," started "+count);
if(count==1){
Log.i(TAG," is front");
callback.onFront();
isFront = true;
}
}
@Override
public void onActivityResumed(Activity activity) {
//1.有執(zhí)行過onPause
//2.不是重復(fù)事件
//3.不是第一次進入onResume
if(isPaused&&!isFront&&isResumed){
if(count==1){
Log.i(TAG," is front");
callback.onFront();
}
}
isPaused = false;
isResumed = true;
isFront = false;
}
@Override
public void onActivityPaused(Activity activity) {
isPaused = true;
}
@Override
public void onActivityStopped(Activity activity) {
count--;
Log.i(TAG," stopped "+count);
if(count==0){
Log.i(TAG," is background");
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
});
}
}
使用該工具類的方式如下:
OnFrontUtil.listenOnFront(this, new OnFrontUtil.OnFrontCallback() {
@Override
public void onFront() {
//數(shù)據(jù)上報梨睁,App回到前臺
}
});