你的位置:首页 > 操作系统

[操作系统]Android清单文件详解(三)


<application>节点是AndroidManifest.

 

 

1.<application>节点配置

 

 

一般来说,在生成Android应用程序的时候,默认的AndroidManifest.

 

 

<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>

 

 

2.如何实现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.

 

 

从图中可以看出来,Android先创建的MyApplication,最后才创建的MainActivity。

 

 

 

3.Application提供的函数及其用法

 

 

android.app.Application类提供了许多类似onCreate()的方法,它们会在不同的场景下被Android框架回调。与此同时,Application类还提供了一些监控的函数,用于监视本应用中组件的生命周期。如下表所示:

 

 

方法名称                                               返回值                  
注解
onConfigurationChanged(Configuration newConfig)void 如果组件正在运行时设备配置(包括语种,方向,网络等)发生改变,则由系统调用此方法通知应用程序
onCreate()void当应用程序正在启动时,并且在创建任何其他应用程序对象之前,调用此方法。由于花费在此功能上的时间直接影响了启动一个进程中首个Activity服务或者接收器的速度,所以尽可能快地执行(例如使用缓慢的初始化状态)。如果你重写了这个方法,需要确保调用super.onCreated()
需要注意的是,在实际应用程序中,如果你的应用程序中的某些组件指定了一个process属性(进程),并且此进程并不存在,那么Application的onCreate()回调就会被调用,换句话说,此方法可能会被多次调用
onLowMemory()void当整个系统正在低内存运行时,并且希望应用程序缩减使用内存的时候,系统调用此方法通知应用程序。但调用此方法的准确点没有定义时,通常它将在所有后台进程已经终止的时间附近发生。
应用程序可执行此方法来释放任何缓冲或其拥有的不必要的资源。系统在从此方法中返回后运行垃圾回收操作。
onTerminate()void 此方法在仿真进程环境中使用,不在生产Android设备上调用,在生产Android设备上,可以通过简单地终止进程来移除进程。进行移除工作时,则不执行任何用户代码(包括此回调)
onTrimMemory()void回收内存的时候调用。例如,当它进入后台并且没有足够内存保持许多后台进程运行时。
监控回调接口
registerComponentCallbacks
unregisterComponentCallbacks
void

void
在应用程序中注册一个ComponentCallbacks接口。在Activity生命周期发生改变之前,通过此接口的各个方法通知应用程序。使用这个接口,我们可以在Activity生命周期发生改变之前做一些必要的处理
需要大家注意的是,必须确保在未来恰当的时候使用unregisterComponentCallbacks(ComponentCallbacks)移除ComponentCallbacks对象,它是我们之前用registerComponentCallbacks(ComponentCallbacks)注册的。

 

 

接下来,我们通过一些实例来说明如何使用这些方法和接口

 

①使用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类型的对象中
mccIMSI的移动国家码,如果是0,表示未定义。
注意:IMSI是指国际移动用户识别码,它存储在我们的SIM卡中,其总长度不超过15位。
数据类型:整型
mncIMSI的移动网络号,如果是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个取值。
0.ORIENTATION_UNDEFINED(未定义的方法)
1.ORIENTATION_PORTRAIT(竖屏方向,屏幕宽度小于高度)
2.ORIENTATION_LANDSCAPE(横屏方向,屏幕宽度大于高度)
3.ORIENTATION_SQUARE(正方形屏幕,认为屏幕宽度等于高度)
注意:在窗口管理服务(WindowManagerService)中计算新配置时,orientation的默认配置是ORIENTATION_SQUARE
数据类型:整型
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(手指触屏模式)
uiModeUI模式的位掩码,目前有两个字段。
⒈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:定义了屏幕是否在一个特殊模式中。它支持如下取值。
UI_MODE_NIGHT_UNDEFINED:未定义模式
UI_MODE_NIGHT_NO:非夜晚模式
UI_MODE_NIGHT_YES:夜晚模式

 

 

下面我们通过一个实例来说明当设备配置发生变化的时候,系统如何通过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.

 

㈢设备运行应用程序,就可以看到如下的日志信息了。

 

 

对于日志,说明如下:

 

日志信息的第一行是初始状态下的方向配置,通过上图我们知道最初的方向值是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秒,程序并没有崩溃,而是等待下去,直到程序正常。当这样会造成不好的用户体验。所以在以后开发过程中,要充分考虑到这些容易出错的情况。

 

③使用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.

 

 

 

 

这里我们通过接口监视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()的用法是一样的,这里就不单举例说明了。