Application

一、概念理解

Base class for maintaining global application state. You can provide your own implementation by creating a subclass and specifying the fully-qualified name of this subclass as the "android:name" attribute in your AndroidManifest.xml's <application> tag. The Application class, or your subclass of the Application class, is instantiated before any other class when the process for your application/package is created.

Note: There is normally no need to subclass Application. In most situations, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), include Context.getApplicationContext() as a Context argument when invoking your singleton's getInstance() method.

Application是维持全局应用状态的基类,单例模式,且先于其他任意组件被创建。Application组件被设计的初衷是对整体应用级别管理负责,对其正确使用应该避免两个极端

  1. 过度使用——将Application当做单例工具类,耦合太多非应用级别的工具方法或业务逻辑,造成Application类臃肿
  2. 从不使用——因不熟悉而不敢使用或忘记使用,不使用没有错,但有时适当使用会减少代码重复,提升性能,且其自身扩展方法也会为某些特殊业务提供思路

Application实际上继承自Context,继承来的方法不必多说,也不是重点。既然有必要子类化,那它也必然会扩展自己的方法来实现其特有功能,也就是和应用管理相关方法。下面将重点介绍这些方法。


二、Application实战应用

Application的应用管理相关功能可以从其维护的三个List来分析:

    private ArrayList<ComponentCallbacks> mComponentCallbacks = new ArrayList<ComponentCallbacks>();//系统配置变更、内存管理
    private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks = new ArrayList<ActivityLifecycleCallbacks>();//Activity生命周期管理
    private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null; //协助数据

(1)ComponentCallbacks/ComponentCallbacks2

用于系统配置变化、内存紧张时获得回调。该接口并非只有Application实现,Activity和Service等其他组件都有实现。而且还可以自定义实现接口,通过API注册。

    void onConfigurationChanged(Configuration newConfig);//系统状态配置如横竖屏、语言等变化时回调
    void onLowMemory();//后台进程被杀后回调
    void onTrimMemory(@TrimMemoryLevel int level);//根据不同内存状态来回调

其中onLowMemory和onTrimMemory的区别:

  1. OnLowMemory被回调时,已经没有后台进程;而onTrimMemory被回调时,还有后台进程。
  2. OnLowMemory是在最后一个后台进程被杀时调用,一般情况是low memory killer 杀进程后触发;OnTrimMemory的触发更频繁,每次计算进程优先级时,只要满足条件,都会触发。
  3. 通过一键清理后,OnLowMemory不会被触发,而OnTrimMemory会被触发一次。

(2)ActivityLifecycleCallbacks

该接口用于对应用所有Activity的生命周期做集中回调管理,是Application独有扩展功能。注册该接口后每个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);
        }

实现原理也比较简单,以onActivityCreated为例, 在Application中有如下方法两个方法

    //注册回调
    public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback)
    //分发回调
    /* package */ void dispatchActivityCreated(Activity activity, Bundle savedInstanceState)

通过registerActivityLifecycleCallbacks方法注册回调,查看Activity源码,当onCreate时,再通过dispatchActivityCreated方法分发给各回调。

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        ...
        getApplication().dispatchActivityCreated(this, savedInstanceState);
        ...
    }

在实际应用中,通过注册registerActivityLifecycleCallbacks回调,可以对Activity的状态和数量做更精准的监控。

应用一:限制Activity实例数量

比如,我们要限制ActivityDetail页面的数量不超过MAX_ACTIVITY_DETAIL_NUM,可以在onActivityCreated回调方法中做如下处理(这是Activity启动模式无法做到的)

    public static Stack<ActivityDetail> store;   
    @Override 
    public void onActivityCreated(Activity activity, Bundle bundle) {
        if (activity instanceof ActivityDetail) {
            if (store.size() >= MAX_ACTIVITY_DETAIL_NUM) {
                store.peek().finish(); //移除栈底并finish,保证不超过指定数量 
            }
            tore.add((ActivityDetail) activity);
        }
    }

应用二:控制相同内容的Activity只有一个实例

比如,要展示商品A的ActivityDetail实例已经存在,就没必要再创建一个展示相同内容的ActivityDetail。

系统级应用可以调用如下方法(需要Android.permission.STOP_APP_SWITCHES权限)

    for(ActivityDetail activityDetail : store){ 
        if(id.equalsIgnoreCase(activityDetail.getID())){ //当前商品id相同证明已有相同页面
             ActivityManager am = (ActivityManager) getAppContext().getSystemService(Activity.ACTIVITY_SERVICE); 
             am.moveTaskToFront(activityDetail.getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION); 
             return true;
        }
    }

非系统级应用只能finish掉已经存在的页面,重新打开一个新的页面

    for(ActivityDetail activityDetail : store){ 
        if(id.equalsIgnoreCase(activityDetail.getID())){ //当前商品id相同证明已有相同页面
             activityDetail.finish();
             return true;
        }
    }

应用三:判断App前后台状态

每当一个Activity切到前台时都会执行onStart,切到后台时都会执行onStop,所以只需要在onActivityStarted和onActivityStopped回调中做一个简单的计数器即可

          mActivityCount = 0;        
          registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
                            ... 
                @Override
                public void onActivityStarted(Activity activity) {
                    Log.d(TAG,"onActivityStarted");
                    mActivityCount++;
                }
     
                @Override
                public void onActivityStopped(Activity activity) {
                    Log.d(TAG,"onActivityStopped");
                    mActivityCount--;
                }
                            ...
            });

当mActivityCount == 0时App为后台,否则即是前台。

posted @ 2019-05-10 16:45  西贝雪  阅读(1191)  评论(0编辑  收藏  举报