7.3 Activity的别名

源代码目录:src/ch07/ActivityAlias

在AndroidManifest.xml文件中除了可以使用<activity>标签声明窗口外,还可以用更灵活的方式设置窗口的属性以及Action、Category等信息。这种灵活的方式就是本节要介绍的Activity别名。

Activity别名使用<activity-alias>标签声明。尽管将该技术称为Activity别名,但更像窗口设置的继承与覆盖。这是因为<activity-alias>标签必须使用targetActivity属性指定一个窗口名,也就是某一个<activity>标签的name属性值。除了targetActivity属性外,<activity-alias>标签的其他属性与<activity>标签的相应属性的含义完全一样。如果未设置<activity-alias>标签的某个属性,该属性值就会使用targetActivity属性值指定的<activity>标签中相应的属性值,也就是<activity-alias>标签的属性默认会继承与其对应的<activity>标签中相应的属性值。<activity-alias>标签支持的主要属性<activity-alias>并不支持<activity>的所有属性。<activity-alias>标签相应属性的含义请参阅6.1节<activity>标签相应属性的介绍。如下。

android:enabled。

android:exported。

android:icon。

android:label。

android:name。

android:permission。

Activity别名的用处比较广泛。例如,在5.1.1小节Activity的基本用法中介绍了如果在一个应用程序中(同一个<application>标签中)的多个窗口类声明中包含如下<intent-filter>标签,系统会在程序列表中生成多个图标,也就是只要安装该程序,就会一下出现多个程序图标,就像安装了多个程序一样。当单击某一个程序图标后就会显示与其对应的窗口。

<intent-filter>

  <action android:name="android.intent.action.MAIN" />

  <category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

其实这种方法实际上可以通过不同的程序图标显示不同的窗口,那么如果要使用同一个窗口处理不同的业务逻辑呢?要实现这个需求,就要使用<activity-alias>标签为某个窗口定义一个别名。例如,在本例中有一个ActivityAliasMain类,该类是主窗口类,现在要使用ActivityAliasMain窗口处理两个不同的逻辑,也就是说一个主窗口要在程序列表中显示两个图标。实现这个需求需要使用到<activity-alias>标签,代码如下:

源代码文件:src/ch07/ActivityAlias/AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

  package="mobile.android.activity.alias"

  android:versionCode="1"

  android:versionName="1.0" >

  ……

  <application……>

    <!-- 第1个主窗口 -->

    <activity

      android:name=".ActivityAliasMain"

      android:label="@string/title_activity_activity_alias_main" >

      <intent-filter>

        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />

      </intent-filter>

    </activity>

    <!-- 第1个主窗口的别名 -->

    <activity-alias

      android:name=".AliasMain"

      android:icon="@drawable/umbrella"

      android:label="AliasMain"

      android:targetActivity="ActivityAliasMain">

      <intent-filter>

        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />

      </intent-filter>

    </activity-alias>

    <!-- 第2个主窗口 -->

    <activity

      android:name=".MyActivity"

      android:icon="@drawable/calculator"

      android:label="Calculator" >

      <intent-filter>

        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />

      </intent-filter>

    </activity>

    ……

  </application>

</manifest>

在上面的代码中声明了两个主窗口,并为第一个主窗口定义了别名。该别名也使用了与主窗口同样的<intent-filter>标签。<activity-alias>标签的android:targetActivity指定了该标签定义了哪个窗口的别名。当运行程序后,会在程序列表中显示3个图标,如图7-26白框中所示,其中单击左上角的两个图标,都会显示ActivityAliasMain窗口,而单击另一个图标会显示MyActivity窗口。

 

▲图7-26 一个应用程序产生3 个图标

为了使用同一个窗口(ActivityAliasMain)处理两个逻辑(例如,装载不同的布局文件),可以通过窗口类名如果系统使用了<activity-alias>标签中的设置,那么获取的窗口类名就是<activity-alias>标签的android:name属性值。(也就是android:name属性值)来判断用户单击的是哪个程序图标。例如,可以在ActivityAliasMain.onCreate方法中获取窗类口名并进行判断。

源代码文件:src/ch07/ActvityAlias/src/mobile/android/activity/alias/ActivityAliasMain.java

  public void onCreate(Bundle savedInstanceState)

  {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_activity_alias_main);

    // 比较窗口类名

    if(".ActivityAliasMain".equals(getComponentName().getShortClassName()))

    {

      setTitle("使用了<activity>标签");

      // 可以在这里完成相应的业务逻辑

    }

    else if(".AliasMain".equals(getComponentName().getShortClassName()))

    {

      setTitle("使用了<activity-alias>标签");

      // 可以在这里完成相应的业务逻辑

    }

 

  }

Activity别名除了前面的应用外,还可以为任何一个窗口定义别名。例如,如果某一个窗口定义了若干个Action,而且要单独控制某一个Action是否可以被其他应用程序调用,这也要使用Activity别名。

在下面的代码中声明了一个TestActivity窗口,并为该窗口定义了一个窗口别名。该别名指定了一个action和category,并且可以通过android:exported属性决定是否可以通过其他程序调用TestActivity窗口。

源代码文件:src/ch07/ActivityAlias/AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

  package="mobile.android.activity.alias"

  android:versionCode="1"

  android:versionName="1.0" >

  ……

    <activity

      android:name=".TestActivity"

      android:label="TestActivity" />

    <!-- 窗口的别名 -->

    <activity-alias

      android:name=".TestActivityAlias"

      android:exported="true"

      android:targetActivity=".TestActivity">

      <intent-filter>

        <action android:name="android.intent.action.TEST_ACTION" />

        <category android:name="android.intent.category.DEFAULT" />

      </intent-filter>

    </activity-alias>

  </application>

</manifest>

如果按照上面的设置,在任何程序中都可以使用下面的代码调用TestActivity窗口。

Intent intent = new Intent("android.intent.action.TEST_ACTION");

startActivity(intent);

使用<activity-alias>别名时应注意如下几点。

<activity-alias>标签的大多数属性都是可选的,但android:name和android:targetActivity属性必须设置。

android:name属性不能与android:targetActivity属性指定的<activity>标签的android:name属性值相同,否则尽管不会抛出异常,但该窗口别名将不再起作用。

android:targetActivity属性指定的<activity>标签必须在<activity-alias>标签之前声明,否则无法将程序安装到Android设备上。