<application>节点是AndroidManifest.xml文件里必须持有的一个节点,它包括在<manifest>节点下。通过<application>节点的相关属性,我们能够声明Android应用程序的相关特性。这个节点包括全部应用程序组件的节点,包括Activity,服务,广播接收器和内容提供者。而且包括了一些可能影响全部组件的属性。这些属性中的当中一些又会作为默认值而被设置到应用程序组件的同样属性上,比方icon,label,permission,process,taskAffinity和allowTaskReparenting等,而其它的一些值则作为应用程序的总体被设置,而且不能被应用程序组件的属性覆盖,比方debuggable,enabled,description和allowClearUserData等。
一般来说。在生成Android应用程序的时候。默认的AndroidManifest.xml文件里就已经包括了一些默认的<application>节点,当中包括应用程序的基本属性。
如今我们就来看看<application>节点信息的全集,代码例如以下:
<application android:allowTaskReparenting=["true"|"false"]
android:backupAgent="string"
android:debuggable=["true"|"false"];
android:description="string resource"
android:enabled=["true"|"false"]
android:hasCode=["true"|"false"]
android:hardwareAccelerated=["true"|"false"]
android:icon="drawable reource"
android:killAfterRestore=["true"|"false"]
android:label="string resource"
android:logo="drawable resource"
android:manageSpaceActivity="string"
android:name="string"
android:permission="string"
android:persistent=["true"|"false"]
android:process="string"
android:restoreAnyVersion=["true"|"false"]
android:taskAffinity="string"
android:theme="resource or theme">
</application>
首先要介绍的是android:name属性,它指的是Application类的子类,当应用程序进程被启动的时候,由android:name属性指定的类将会在全部应用程序组件(activity,服务,广播接收器,内容提供者)被实例化之前实例化。
普通情况下。应用程序无需指定这个属性,Android会实例化Android框架下的applicaiton类。
然而。在一些特殊的情况下。比方希望在应用程序组件启动之前就完毕一个初始化工作。或者在系统低内存的时候做一些特别的处理,就要考虑实现自己的Application类的一个子类。
在Android系统提供的系统应用中。就有一个实现了自己的Application实例。这个应用程序就是Launcher。
我们能够仿照它来实现一个自己的Application类。详细过程例如以下。
①创建一个叫做ApplicationTest的项目,而且在默认生成的MainActivity里的onCreate()方法中加入一行代码来输出一条日志。这样就能够看到Application创建时间,详细代码例如以下:
public class MainActivity extends Activity { private static final String TAG="MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.e(TAG,"MainActivity is created"); } }
②实现自己的MyApplication类,代码例如以下:
public class MyApplication extends Application { private static final String TAG="MyApplication"; @Override public void onCreate() { super.onCreate(); Log.e(TAG,"MyApplication is created"); } }
③将MyApplication加入到清单文件AndroidManifest.xml中<application>内android:name中
从图中能够看出来,Android先创建的MyApplication,最后才创建的MainActivity。
android.app.Application类提供了很多类似onCreate()的方法,它们会在不同的场景下被Android框架回调。与此同一时候,Application类还提供了一些监控的函数,用于监视本应用中组件的生命周期。例如以下表所看到的:
方法名称 | 返回值 | 注解 |
onConfigurationChanged(Configuration newConfig) | void | 假设组件正在执行时设备配置(包含语种,方向。网络等)发生改变,则由系统调用此方法通知应用程序 |
onCreate() | void | 当应用程序正在启动时,而且在创建不论什么其它应用程序对象之前。调用此方法。 因为花费在此功能上的时间直接影响了启动一个进程中首个Activity服务或者接收器的速度,所以尽可能快地运行(比如使用缓慢的初始化状态)。假设你重写了这种方法,须要确保调用super.onCreated() |
onLowMemory() | void | 当整个系统正在低内存执行时,而且希望应用程序缩减使用内存的时候,系统调用此方法通知应用程序。 但调用此方法的准确点未定义时,通常它将在全部后台进程已经终止的时间附近发生。 系统在从此方法中返回后执行垃圾回收操作。 |
onTerminate() | void | 此方法在仿真进程环境中使用,不在生产Android设备上调用。在生产Android设备上,能够通过简单地终止进程来移除进程。进行移除工作时,则不运行不论什么用户代码(包含此回调) |
onTrimMemory() | void | 回收内存的时候调用。比如,当它进入后台而且没有足够内存保持很多后台进程执行时。 |
监控回调接口 registerComponentCallbacks unregisterComponentCallbacks |
void void |
在应用程序中注冊一个ComponentCallbacks接口。 在Activity生命周期发生改变之前,通过此接口的各个方法通知应用程序。使用这个接口。我们能够在Activity生命周期发生改变之前做一些必要的处理 |
接下来。我们通过一些实例来说明怎样使用这些方法和接口
①使用onConfigurationChanged()方法监听系统配置更新
onConfigurationChanged()方法的函数原型例如以下:
public void onConfigurationChanged(Configuration newConfig){}当中newConfig參数表示新的设备配置
onConfigurationChanged()方法是一个回调接口。在设备配置发生变化时由Android系统调用。与此同一时候,Android系统会通过參数(newConfig)传给应用程序,由应用程序处理这个变化。
注意,不同于Activity,其它组件在一个配置改变时从不又一次启动。它们孙弱自己处理改变的结果。这里所述的“配置”例如以下表所看到的:
配置项 | 注解 |
fontScale | 表示当前的系统的字体缩放比例。它是基于像素密度缩放的。 注意。在使用用户模式编译出来的系统固件中,不包括改动此项配置的界面,仅仅能通过编程的方法去改变。 数据类型:浮点型 |
hardKeyBoardHidden | 指示硬键盘是否被隐藏起来。此配置项有3个取值。详细例如以下所看到的。 0.HARDKEYBOARDHIDDEN_UNDEFINED(Android无法识别的键盘状态) 1.HARDKEYBOARDHIDDEN_NO(硬键盘可用) 2.HARDKEYBOARDHIDDEN_YES(硬键盘被隐藏) 数据类型:整型 |
keyboard | 指示加入到设备上的是哪个种类的键盘,此配置项有下面4个取值 0.KEYBOARD_UNDEFINED(Android无法识别的键盘) 1.KEYBOARD_NOKEYS(无按键键盘) 2.KEYBOARD_QWERTY(打字机键盘) 3.KEYBOARD_12KEY(12键键盘) 数据类型:整型 |
keyboardHidden | 指示当前是否有键盘可用。假设在有硬键盘的Android设备中,硬键盘被收起,而仍有软键盘。则觉得键盘是可用的。这个字段有例如以下3个取值。 0.KEYBOARDHIDDEN_UNDEFINED(Android无法识别的键盘状态) 1.KEYBOARDHIDDEN_NO(仍有软键盘可见) 2.KEYBOARDHIDDEN_YES(全部的软键盘都被隐藏)。
|
locale | 定义了设备的语言环境。 它包括了国家以及语言信息。这些信息被包括在一个java.util.Locale类型的对象中 |
mcc | IMSI的移动国家码。假设是0,表示没有定义。 注意:IMSI是指国际移动用户识别码。它存储在我们的SIM卡中,其总长度不超过15位。 数据类型:整型 |
mnc | IMSI的移动网络号,假设是0表示没有定义 数据类型:整型 |
navigation | 指示当前设备可用的导航方式,它有例如以下5个取值。 0.NAVIGATION_UNDEFINED(没有定义的导航方式) 1.NAVIGATION_NONAV(无导航) 2.NAVIGATION_DPAD(面板导航方式) 3.NAVIGATION_TRACKBALL(轨迹球导航) 4.NAVIGATION_WHEEL(滚轮方式导航) 数据类型:整型 |
navigationHidden | 用于指示导航是否可用。有例如以下取值。 0.NAVIGATIONHIDDEN_UNDEFINED 1.NAVIGATIONHIDDEN_NO 2.NAVIGATIONHIDDEN_YES 数据类型:整型 |
orientation | 指示屏幕方向的标志,有例如以下4个取值。
|
screenHeightDp | 屏幕可用部分的高度 |
screenLayout | 指示屏幕的总体属性,它包含两个部分。 ⒈SCREENAYOUT_SIZE_MASK:标志屏幕大小的属性(比方大屏幕,小屏幕等),它有下面5个取值。 SCREENAYOUT_SIZE_UNDEFINED:没有定义(值:0) SCREENAYOUT_SIZE_SMALL:小屏幕(值:1,屏幕分辨率至少为320*426)。 SCREENAYOUT_SIZE_NORMAL:普通屏幕(值:2,屏幕分辨率至少为320*470) SCREENAYOUT_SIZE_LARGE:大屏幕(值:3,屏幕分辨率至少为480*640) SCREENAYOUT_SIZE_XLARGE:加大屏幕(值:4,屏幕分辨率至少为720*960) ⒉SCREENAYOUT_LONG_MASK:指示屏幕是否比通常情况上更高或者更宽,它有例如以下3个取值。 SCREENAYOUT_LONG_UNDEFINED:没有定义(十六进制值为0) SCREENAYOUT_LONG_YES:是(十六进制值为20) SCREENAYOUT_LONG_NO:否(十六进制值为10) |
screenWidthDp | 屏幕可用部分的宽度 |
smallestScreenWidthDp | 在正常操作中。应用程序将会看到最小的屏幕尺寸。 这是在竖屏和横屏中screenWidthDp和ScreenHeightDp的最小值。 |
touchscreen | 设备上触摸屏的种类。它支持例如以下取值。 0.TOUCHSCREEN_UNDEFINED(没有定义模式) 1.TOUCHSCREEN_NOTOUCH(无触屏模式) 2.TOUCHSCREEN_STYLUS(手写笔模式) 3.TOUCHSCREEN_FINGER(手指触屏模式) |
uiMode | UI模式的位掩码,眼下有两个字段。 ⒈UI_MODE_TYPE_MASK:定义了设备的整个UI模式,它支持例如以下取值。 UI_MODE_TYPE_UNDEFINED:未知模式 UI_MODE_TYPE_NORMAL:通常模式 UI_MODE_TYPE_DESK:带底座模式‘ UI_MODE_TYPE_CAR:车载模式 ⒉UI_MODE_NIGHT_MASK:定义了屏幕是否在一个特殊模式中。 它支持例如以下取值。 |
以下我们通过一个实例来说明当设备配置发生变化的时候。系统怎样通过onConfigurationChanged回调接口来通知应用程序的。
㈠为前面的应用程序加入一个名叫ConfigApplication的Application的子类,并实现onCreate()方法及onConfigurationChanged()方法。
在onCreate()方法中,我们会获取应用程序在创建之初所拥有的配置信息。而在onConfigurationChanged()方法中,则能够加入一些代码以便用日志的方式来实时体现配置更新。相关代码例如以下:
public class ConfigApplication extends Application { private static final String TAG="ConfigApplication"; private Configuration mConfiguration; @Override public void onCreate() { super.onCreate(); this.mConfiguration=getResources().getConfiguration();//获取配置信息 Log.e(TAG,"onCreate::infomation:orientation="+this.mConfiguration.orientation); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //打印更新后的配置信息 Log.e(TAG,"onConfigurationChanged:infomation:orientation="+newConfig.orientation); } }
㈡按前文所述,将ConfigApplication配置到AndroidManifest.xml文件里。
㈢设备执行应用程序,就能够看到例如以下的日志信息了。
对于日志,说明例如以下:
日志信息的第一行是初始状态下的方向配置。通过上图我们知道最初的方向值是1。
而依据前面的表。可知当前是竖屏方向。
日志信息的第五行是切换横屏后。Android系统回调了我们实现的onConfigurationChanged()方法,这时系统配置已经发生了改变,因此这里的日志打印了当前的屏幕方向是2。也是就横屏。
建议:因为基类onConfigurationChanged()方法中实现了对一些回调接口的调用。所以假设我们重写了这种方法。那么为了维持原Application类的行为,建议在重写的方法入口调用super.onConfigurationChanged(newConfig)。
②使用onCreate()完毕应用程序初始化
onCreate()方法的原型为:
public void onCreate(){}
如前面的表所看到的,onCreate()方法是一个回调接口。Android系统会在应用程序启动的时候,在不论什么应用程序组件(Activity,服务,广播接收器,内容提供者)被创建之前调用这个接口。
须要注意的是,这种方法的运行效率会直接影响到启动Activity。服务。广播接收器,或者内容提供者的性能,因此该方法应尽可能快地完毕。
最后。假设实现了这个回调接口。请前晚不要忘记调用super.onCreate(),否则应用程序会报错。
前面我们实现了Appplication类的子类------Configuration,而且也已经实现了自身的onCreate()方法。这里来做个小实验。让大家更清楚这些知识。
如今,在源码的onCreate()方法中增加一个大约20秒的等待。以此来模拟在onCreate()方法中做了过于繁重的工作而导致该方法长时间无法完毕的情况,改动后的代码例如以下:
public class ConfigApplication extends Application { private static final String TAG="ConfigApplication"; private Configuration mConfiguration; @Override public void onCreate() { super.onCreate(); this.mConfiguration=getResources().getConfiguration();//获取配置信息 Log.e(TAG,"onCreate::infomation:orientation="+this.mConfiguration.orientation); SystemClock.sleep(20000);//沉睡20秒 } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //打印更新后的配置信息 Log.e(TAG,"onConfigurationChanged:infomation:orientation="+newConfig.orientation); } }
此时执行程序,程序就会崩溃,当然,在真实的设备上,是能够等待的,有的并不会造成崩溃,比方经在小米上測试50秒,程序并没有崩溃,而是等待下去,直到程序正常。
当这样会造成不好的用户体验。所以在以后开发过程中。要充分考虑到这些easy出错的情况。
③使用onLowMemory()回调方法监视低内存
该方法的原型为:
public void onLowMemory(){}
当整个系统在低内存执行时,将调用该方法。
好的应用程序会实现该方法来释放不论什么缓存或者其它不须要的资源。系统从该方法返回之后,将运行一个垃圾回收操作。
④使用registerActivityLifecycleCallbacks()注冊能够监视Activity生命周期的接口
registerActivityLifecycleCallbacks()方法的原型为:
public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback){}
在该方法中,參数callbacks表示Activity生命周期的接口。
从Android4.0以后,Android SDK为应用程序提供了一套完整的接口以便监视与本Application相关的Activity的生命周期(创建,启动以及暂停等),它的名字叫做ActivityLifecycleCallbacks。
仅仅要在Application中通过registerActivityLifecycleCallbacks()方法将接口注冊上。它就会通过ActivityLifecycleCallbacks提供应用程序中相关的Activity生命周期信息。下表列出了这些接口以及用途。
方法原型 | 參数说明 | 用途 |
abstract void onActivityCreated(Activity activity,Bundle savedInstanceState) | activity:创建的Activity实例 savedInstanceState:创建该Activity时所带的信息(一个Bundle实例) |
在应用程序创建Activity之前调用,用于通知接口实现者Activity将要被创建。 |
abstract void onActivityDestroyed(Activity activity) | activity:销毁的Activity实例 | 在应用程序销毁Activity之前调用,用于通知接口实现者Activity将要被销毁。 |
abstract void onActivityPaused(Activity activity) | activity:暂停的Activity实例 | 在应用程序暂停Activity之前调用,用于通知接口实现者Activity将要被暂停。 |
abstract void onActivityResumed(Activity activity) | activity:恢复的Activity实例 | 在应用程序正在恢复Activity之前调用,用于通知接口实现者Activity将要被恢复。 |
abstract void onActivitySaveInstanceState(Activity activity,Bundle outState) | activity:正在运行状态保存的的Activity实例 outState:须要保存的Activity状态 |
指示当前Activity正在保存自己的状态,这些状态包括在outState中。 |
abstract void onActivityStarted(Activity activity) | activity:启动的Activity实例 | 在应用程序正在启动Activity之前调用。用于通知接口实现者Activity将要被启动。 |
abstract void onActivityStopped(Activity activity) | activity:停止的Activity实例 | 在应用程序正在停止Activity之前调用,用于通知接口实现者Activity将要被停止。 |
特别提醒:从接口定义中,我们能够知道例如以下信息。
Ⅰ这些接口都是抽象的,因此当我们实现ActivityLifecycleCallbacks接口时,就必须实现这些方法,哪怕仅仅是空实现。
Ⅱ这些接口的返回值都是void,这说明它们仅仅用于通知,别无它用。
另外我们在必要时要调用unregisterActivityLifecycleCallbacks()方法来注销掉原先注冊的接口以免造成不必要的资源浪费。
以下我们通过一个实例来说明配置发生变化的时候。系统怎样通过onConfigurationChanged()回调接口来通知应用程序,详细的过程例如以下所看到的。
㈠实现自己的Application子类(名叫ALCApplication)。
我们将在应用程序创建(onCreate()方法中)时注冊自己的Activity生命周期接口。在程序终止(onTerMinate()方法中)时注销这个接口。当完毕这些工作以后,将得到例如以下所看到的的代码:
public class ALCApplication extends Application { private final static String TAG="ALCApplication"; private ActivityLifecycleCallbacks mActivityLifecycleCallbacks=new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { Log.e(TAG,"onActivityCreated"); } @Override public void onActivityStarted(Activity activity) { Log.e(TAG,"onActivityStarted"); } @Override public void onActivityResumed(Activity activity) { Log.e(TAG,"onActivityResumed"); } @Override public void onActivityPaused(Activity activity) { Log.e(TAG,"onActivityPaused"); } @Override public void onActivityStopped(Activity activity) { Log.e(TAG,"onActivityStopped"); } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { Log.e(TAG,"onActivitySaveInstanceState"); } @Override public void onActivityDestroyed(Activity activity) { Log.e(TAG,"onActivityDestroyed"); } }; @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(this.mActivityLifecycleCallbacks); } @Override public void onTerminate() { super.onTerminate(); unregisterActivityLifecycleCallbacks(this.mActivityLifecycleCallbacks); } }
㈡将ALCApplication配置到AndroidManifest.xml中。当配置完毕时。最后的结果看起来与下图类似:
这里我们通过接口监视Activity从启动到推出的生命周期。
在这个实例中,我们在onTerminate()方法中做了注销接口的工作。但值得注意的是。onTerminate()方法仅仅会在虚拟机进程中被调用,永远不会在真实的Android设备中被调用。
⑤使用registerComponentCallbacks()注冊一个能够用来舰艇Activity生命周期的接口
该方法原型为:
public void registerComponentCallbacks(ComponentCallbacks callback){}
当中參数callback是ComponentCallbacks 接口的一个实现。当Activity的生命周期发生变化时。会通过这个接口通知应用程序。对于全部应用程序来。它是通用的回调API集合的接口。ComponentCallbacks中仅仅包含两个方法,它们各自是public abstract void onConfigurationChanged(Configuration newConfig)和public abstract void onLowMemory()。
这两个方法的调用与Application中的同名回调方法的调用条件一样的。
ComponentCallbacks()和registerComponentCallbacks()方法的使用方法与ActivityLifecycleCallbacks()和registerActivityLifecycleCallbacks()的使用方法是一样的,这里就不单举例说明了。