APP前后台切换那些事

2020-01-16 Views android

监听app前后台切换对于App来说是一个比较实用的功能。一些功能的实现离不开前后台切换的时机,比如App进入前台检查剪切板、统计用户在线时间等等。下面本文就从前后台切换监听说起。

App前后台切换,本质上就是当前App任务栈顶页面的onPause和onResume方法被调用了,并且页面onPause后回到了桌面或者切换到其他App。在Android系统中并未有App到前后台相关的广播,因此我们只能在App自己实现相关的监听方法。

方案1

在App的基类BaseActivity中监听Activity的onStart和onStop方法。在onStart方法内部记录当前类名和hash值,并且在onStop方法内将记录拿出对比,若类名和hash值一致,则说明App没有进行页面内的跳转,而是被用户切换到后台。

具体实现:

    public void onResume() {
		String topActivityName = PublicPreferencesUtils.getTopActivityName();
		boolean isBackByHome = PublicPreferencesUtils.isBackByHome();
		if(isBackByHome && mActivityName.equals(topActivityName)) {
			// 表示由Home键回到程序,而且程序的进程没有被杀掉
			mHomeClickListener.onClickToFront();
		}

		PublicPreferencesUtils.saveTopActivityName(mActivityName);
		PublicPreferencesUtils.saveBackByHome(false); // 重置
	}

	public void onStop() {
		if(!mActivity.isFinishing()){ // 如果程序没有退出
			String topActivityName = PublicPreferencesUtils.getTopActivityName();
			if(mActivityName.equals(topActivityName)) {
				// 则表示用户按了Home键,程序进入后台运行
				mHomeClickListener.onClickToBack();
				
				// 保存是按Home键进入的后台
				PublicPreferencesUtils.saveBackByHome(true);
			}
		}
	}

这个方案能够监听到App的前后台切换,但也仅限于全部页面继承自BaseActivity才可以准确的获取切换时机。

若有页面没有继承BaseActivity,则获取的监听回调可能是错误的!

方案2

还是在基类BaseActivity中做文章。我们可以在onStop方法里添加对于当前前台进程的判断。若前台进程为当前应用进程,则认为App正在前台显示,否则切换到了后台。

具体实现:

    public boolean isRunningForeground() {
        ActivityManager activityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcessInfos = activityManager.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo appProcessInfo : appProcessInfos) {
            if (appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                if (appProcessInfo.processName.equals(this.getApplicationInfo().processName)) {
                    Log.d(TAG,"App isRunningForeGround");
                    return true;
                }
            }
        }
        Log.d(TAG, "App isRunningBackGround");
        return false;
    }

方案3

在Application类中,提供了一个应用生命周期回调的注册方法,用来对应用的生命周期进行集中管理,这个接口叫registerActivityLifecycleCallbacks,可以通过它注册自己的ActivityLifeCycleCallback,每一个Activity的生命周期都会回调到这里的对应方法。其实这个注册方法的本质和我们实现BaseActivity是一样的,只是将生命周期的管理移到了Activity本身的实现中。

public class ForegroundHelper implements Application.ActivityLifecycleCallbacks {
    //launch页标记
    private static final String LAUNCH_ACTIVITY_TAG = LaunchActivity.TAG;
    //当前记录的Activity个数
    private int finalCount;
    //回调listener
    private CopyOnWriteArrayList<AppStatusListener> mListeners;

    private ForegroundHelper() {
        mListeners = new CopyOnWriteArrayList<>();
    }

    public static ForegroundHelper getInstance() {
        return Singleton.mInstance;
    }

    /**
     * 添加监听
     *
     * @param appStatusListener
     */
    public void addAppStatusListener(AppStatusListener appStatusListener) {
        mListeners.add(appStatusListener);
    }

    /**
     * 移除监听
     *
     * @param appStatusListener
     */
    public void removeAppStatusListener(AppStatusListener appStatusListener) {
        mListeners.remove(appStatusListener);
    }
    
    ···省略部分代码···

    @Override
    public void onActivityStarted(Activity activity) {
        finalCount++;
        //如果mFinalCount ==1,说明是从后台到前台
        LOGGER.d("ForegroundHelper", finalCount + "");
        if (finalCount == 1) {
            boolean isAppStart = checkAppStart(activity);
            //说明从后台回到了前台
            LOGGER.d("ForegroundHelper", isAppStart ? "app启动了" : "从后台回到了前台");
            notifyForeground(isAppStart);
        }
    }

    private boolean checkAppStart(Activity activity) {
        boolean result = false;
        if (activity.getClass().getSimpleName().equals(LAUNCH_ACTIVITY_TAG)) {
            result = activity.isTaskRoot();
        }
        return result;
    }
    

    @Override
    public void onActivityStopped(Activity activity) {
        finalCount--;
        //如果mFinalCount ==0,说明是前台到后台
        LOGGER.d("ForegroundHelper", finalCount + "");
        if (finalCount == 0) {
            //说明从前台回到了后台
            LOGGER.d("ForegroundHelper", "从前台到了后台");
            notifyBackground();
        }

    }
    ···省略部分代码···

在Application的onCreate方法中添加registerActivityLifecycleCallbacks(ForegroundHelper.getInstance())即可监听到App前后台启动的时机。

判断启动

为什么要判断启动呢?这里有个概念是从桌面点击icon进入App不算是严格意义上的回到前台,而是启动App到达了前台,因此需要添加一个启动校验放在方法中标识。
若当前启动的是LaunchActivity,并且不在栈底的话,则认为是App启动到了前台。

因此在上述三个方案中都可以按照该方法来监听启动。

    //检查是否是启动App
    private boolean checkAppStart(Activity activity) {
        boolean result = false;
        if (activity.getClass().getSimpleName().equals(LAUNCH_ACTIVITY_TAG)) {
            result = activity.isTaskRoot();
        }
        return result;
    }

相应的,前后台切换监听也要做如下修改:

    /**
     * App前后台切换监听
     */
    public interface AppStatusListener {
        /**
         * app 到前台
         *
         * @param appStart 是否是App 启动
         */
        void onForeground(boolean appStart);

        /**
         * App切换到后台
         */
        void onBackground();
    }

赏 支付宝扫码打赏 微信打赏

△