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以下的,可以考虑增加方案一判断。

  • 相关阅读:
    关于Maya Viewport 2.0 API 开发的介绍视频
    春节大假
    Some tips about the life cycle of Maya thread pool
    Can I compile and run Dx11Shader for Maya 2015 on my side?
    How to get current deformed vertex positions in MoBu?
    想加入全球首届的 欧特克云加速计划吗?
    三本毕业(非科班),四次阿里巴巴面试,终拿 offer(大厂面经)
    mac、window版编辑器 webstorm 2016... 永久破解方法。
    node 搭载本地代理,处理web本地开发跨域问题
    js 一维数组,转成嵌套数组
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/9336663.html
Copyright © 2011-2022 走看看