zoukankan      html  css  js  c++  java
  • Android 监听APP进入后台或切换到前台方案对比

    在我们开发的过程中,经常会遇到需要我们判断app进入后台,或者切换到前台的情况。比如我们想判断app切换到前台时,显示一个解锁界面,要求用户输入解锁密码才能继续进行操作;我们想判断app切换到后台,记录一下log;或者当用户切换回前台时,我们想刷新一下页面的数据等等......

    android里面监听app前后台的方案很多(这还是得归根于安卓提供了丰富的api和强大的架构支撑,呵呵~),比如可以通过ActivityManager提供的getRunningAppProcesses()获取系统当前运行的app,从而判断app是否处于前台。或者通过监听点击Home键,判断app是否回到了后台。下面将针对笔者已知的几种方案,进行对比分析。

    方案一:利用ActivityManager的RunningAppProcessInfo类
    ActivityManager在整个系统里面起着非常重要的作用,主要为系统中运行着的activity交互提供接口,其中RunningAppProcessInfo类则封装了正在运行着的进程信息,当然也包含了正在运行的app的包名,因此我们可以activitymanager.getRunningAppProcesses()获取当前运行的app列表,对比自身的包名,来判断本身app是否处于前台运行。

    这打断一下,ActivityManager框架是Android系统十分重要的一部分,在以后有时间,笔者会好好学习整理ActivityManager框架的分析。

    回到这里,下面给出部分关键代码。

     /**
         * App前后台状态
         */
        public boolean isForeground = false;
        @Override
        protected void onResume() {
            ......
            if (isForeground == false) {
                //由后台切换到前台
                isForeground = true;
            }
        }
     
        @Override
        protected void onPause() {
            ......
            if (!isAppOnForeground()) {
                //由前台切换到后台
                isForeground = false;
            }
        }
        /**
         * 判断app是否处于前台
         *
         * @return
         */
        public boolean isAppOnForeground() {
     
            ActivityManager activityManager = (ActivityManager) getApplicationContext()
                    .getSystemService(Context.ACTIVITY_SERVICE);
            String packageName = getApplicationContext().getPackageName();
            /**
             * 获取Android设备中所有正在运行的App
             */
            List<RunningAppProcessInfo> appProcesses = activityManager
                    .getRunningAppProcesses();
            if (appProcesses == null)
                return false;
     
            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;
                }
            }
     
            return false;
        }

    小结:通过ActivityManager来获取当前运行的app列表,然后判断我们的app是否处于前台,能基本达到我们的预期需求。但如果将上面代码放到每一个activity,或者activity基类里面,这消耗还是挺大的。而且而且,ActivityManager通过.getRunningAppProcesses()获取当前运行列表这个方法,在5.0以后已经被deprecated掉了....(心中万马奔腾...)

    方案二:监听Home键点击

    说起home键的监听,也算是android里面的一个梗。这看上去简单的功能,实际上实现起来却十分的曲折,这跟android系统的设计有很大的关系。当home键被点击的时候,会发出一个系统广播,在系统收到这个广播以后,会在framework层做一系列操作将当前的app退到后台,然后把事件消费掉不传给应用层,所以这时候 onKeyDown事件也接收不到了..用官方的解释就是——“Home key. This key is handled by the framework and is never delivered to applications.”。实际上这也是为了安全性的考虑,不然每家的app都监听home键,然后禁掉响应,不都成了流氓软件了。

    官方不支持,可是这难不到我们万能的攻城狮们的,毕竟有很多想我们正规的开发者,还是需要监听home键来做一些如写日志之类的操作的。网上谷歌百度会有很多类似的解决方案,在这里就不展开了。(不过这里可以推荐一下)

    小结:我们能监听到home键点击,当然就知道app处于前台还是后台了。但毕竟这个方案是基于官方不支持的前提下的,而且home键的监听在很多设备都会有兼容性的问题,因此我们不大推荐这样做。

    方案三:利用ActivityLifecycleCallbacks监听所有activity的生命周期

    通过监听所有activity的onStart、onStop调用,然后统计当前是不是所有的activity都调用了onStop,确实可以判断app处于了后台,不过让我们重写每一个activity的onStop,并加这段奇怪的代码,实在不大优雅,即使在activity基类里面统一写,那天如果忘了或者不需要继承基类的activity,就不大好了。

    因此,这里推荐一个新的接口ActivityLifecycleCallbacks,说新也不新,其实早在API 14 (android 4.0)就已经推出了。ActivityLifecycleCallbacks接口在Application类里面,因此需要我们自己继承Application,自定义一个MyApplication,然后注册接口。ActivityLifecycleCallbacks为application提供了对所有activity生命周期的监听,因此我们通过重写ActivityLifecycleCallbacks的onActivityStarted和onActivityStopped方法,定义一个变量,来统计当前有几个activity处于前台。

      /**
         * 当前Acitity个数
         */
        private int activityAount = 0;
        
        @Override
        public void onCreate() {
            ......
            registerActivityLifecycleCallbacks(activityLifecycleCallbacks);
            ......
        }
     
        /**
         * Activity 生命周期监听,用于监控app前后台状态切换
         */
        ActivityLifecycleCallbacks activityLifecycleCallbacks = new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            }
     
            @Override
            public void onActivityStarted(Activity activity) {
    //            if (activityAount == 0) {
    //                //app回到前台
    //                isForeground = true;
    //            }
                activityAount++;
            }
     
            @Override
            public void onActivityResumed(Activity activity) {
            }
            @Override
            public void onActivityPaused(Activity activity) {
            }
     
            @Override
            public void onActivityStopped(Activity activity) {
                activityAount--;
                if (activityAount == 0) {
                    isForeground = false;
                }
            }
     
            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            }
            @Override
            public void onActivityDestroyed(Activity activity) {
            }
        };

    以上代码写在MyApplication里面。怎么样,是不是很简单快捷!而且准确无误。

    总结:
    1、利用ActivityManager的RunningAppProcessInfo类,直接粗暴,官方摒弃,不推荐;
    2、监听Home键点击,官方不支持,兼容性差,不稳定,不推荐;
    3、利用ActivityLifecycleCallbacks监听所有activity的生命周期,官方指定饮品,哦,不对,官方指定接口,大力推荐!我们举一反三,利用ActivityLifecycleCallbacks监听,我们还能控制我们的activity堆栈,甚至还可以在里面做日志统计...想想还是很强大的。

    PS:虽则利用ActivityLifecycleCallbacks接口监听的方案最优,但这毕竟是4.0以后的产品,因此对于4.0以下的,可以考虑增加方案一判断。

  • 相关阅读:
    MATLAB学习1 之画图函数
    innobackupex 出现Unrecognized character x01; marked by
    innobackupex 出现Unrecognized character x01; marked by
    innobackupex 出现Unrecognized character x01; marked by
    innobackupex 出现Unrecognized character x01; marked by
    企业云桌面-03-安装第1个企业 CA-013-CA01
    python 串行执行和并行执行
    cx_Oracle 查询 传参
    运维工程师要失业了?抛开噱头与调侃,闲聊我心中的运维!
    迭代器
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/9336663.html
Copyright © 2011-2022 走看看