Android中AndroidManifests.xml 之meta-data
一、概念
meta-data( 元数据; 文件元数据)就像其名一样,主要用来定义一些组件相关的配置值。
按照官方定义,metadata是一组供父组件使用的名值对(name-value pair),因此相应的meta-data元素应该定义在相应的组件中。即如果想在activity中使用metadata,那么meta-data必须定义在AndroidManifest.xml的activity声明中。
- AndroidManifests.xml下的meta-data则是对外界开放的,是向系统注册的信息,系统及外界是可以通过PackageInfo相关API获取到meta-data的信息。
- 与strings的区别在于它们的作用域,strings只能在应用本地被读取,很像公有与私有的区别。
meta-data标签的使用在配置文件中配置参数,然后在Context中通过bundle取出参数
1.1 语法
<meta-data android:name="string"
android:resource="resource specification"
android:value="string" />
标签<meta-data>是提供组件额外的数据用的,它本身就是一个键值对,可以自定义名称和值。它可以包含在以下组件当中:
<activity>
<activity-alias>
<application>
<provider>
<receiver>
<service>
1.2 说明
一个以键-值对表示的数据项,以供父组件作为附加数据使用,数据类型任意。 一个组件元素可以包含任意数量的 子元素。 这些子元素的值存放在一个 Bundle 对象中,组件可以通过 PackageItemInfo.metaData 字段访问这些数据。
普通类型的值可以通过 value 属性来给定。 而资源 ID 的值则必须用 resource 属性来指定。 比如,以下代码把“com.android.settings.xxx”的名称赋值为 @string/kangaroo 资源中存储的数据:
<meta-data android:name="com.android.settings.xxx"
android:value="@string/kangaroo" />
另一方面, 通过 Resource 属性将把“com.android.settings.xxx”赋值为资源的 ID ,而不是资源中存储的数据:
<meta-data android:name="com.android.settings.xxx"
android:resource="@string/kangaroo" />
强烈建议不要使用多个独立的 部分定义数据。 如果有比较复杂的数据需要和某个组件关联,请把它们作为资源存储,并用 resource 属性将资源 ID 告知组件。
1.3 属性
- android:name
数据项的唯一名称。 为了确保名称的唯一性,可使用 Java 风格的命名规则 — 如“com.example.project.activity.fred”。 - android:resource
对某个资源的引用。赋值为资源 ID 。 通过 Bundle.getInt() 方法可以从 meta-data Bundle 中读取该资源 ID。 - android:value
赋给数据项的值。 下表列出了可赋予的数据类型、组件用 Bundle 对象获取该类值的方法:
类型 | Bundle 方法 |
---|---|
字符串值,双反斜杠(\)作为转义字符 — 比如“\n”、“\uxxxxx”表示 Unicode 字符 | getString() |
整数值,比如“100” | getInt() |
布尔型值,“true”或“false” | getBoolean() |
颜色值,格式为“#rgb”、“#argb”、“#rrggbb”或“#aarrggbb” | getInt() |
浮点型值,比如“1.23” | getFloat() |
二、使用
所有的名值对被包装成Bundle供组件使用,因此使用方式同Bundle。metadata普通值由value属性给出,资源ID由resource属性给出。
2.1 用法
比如我们定义资源
<string name="x_key">resource key</string>
//R
public static final int ic_launcher=0x7f020000;
定义metadata
<meta-data
android:name="com.xesam.key_1"
android:value="x_key" />
<meta-data
android:name="com.xesam.key_2"
android:value="@string/x_key" />
<meta-data
android:name="com.xesam.img"
android:resource="@drawable/ic_launcher" />
那么有:
metadata.getString("com.xesam.key_1") ==> "x_key"
metadata.getString("com.xesam.key_2") ==> "resource key"
metadata.getInt("com.xesam.img") ==> 0x7f020000
由于resource指向资源ID,因此用metadata可以定义一些稍微复杂的值。
比如要定义一副图片,则可以用这个,然后在代码中用getInt()取出图片的ID:
int imageId = meta.getInt("com.xesam.img");
((ImageView) findViewById(R.id.img)).setImageResource(imageId);
2.2 使用问题
<meta-data
android:name="com.xesam.key_1"
android:value="000" />
类似这样的值如果使用bundle.getString()的话是不起作用的,因为Bundle中使用的是形如:
return (String) o;
代码获取一个StringValue值的,但是在将metadata包装成bundle的时候,"000"被解析成整数0,
因此bundle.getString(“com.xesam.key_1”)返回的是(String)0,显然,java是不允许这样的,因此最后得到的是null。 话说android为什么不是用String.valueOf()或者obj.toString()呢?
为了避免这种情况:
1,可以在形如000的字符串前面放个\0空字符,强迫android按照字符串解析000。
2,在资源文件中指定需要的值,然后在metadata的value中引用此值。
三、 具体应用场景解析
3.1 在activity中
xml中配置如下
<!-- Activity -->
<activity android:name=".MyActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="activity_name"
android:value="activity_value" />
</activity>
java代码如下
//在Activity应用<meta-data>元素。
ActivityInfo actInfo = mContext.getPackageManager().getActivityInfo(
getComponentName(), PackageManager.GET_META_DATA);
String msg = actInfo.metaData.getString("activity_name");
3.2 在service中
xml中配置如下
<!-- 服务 -->
<service android:name=".MyService">
<meta-data android:name="service_name"
android:value="service_value" />
</service>
java代码如下
//在service应用<meta-data>元素。
ComponentName cn = new ComponentName(this, MyService.class);
try {
ServiceInfo serInfo = this.getPackageManager().getServiceInfo(cn,
PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
String msg = serInfo.metaData.getString("service_name");
3.3 在application中
xml中配置如下
<!-- app -->
<meta-data android:name="application_name" android:value="application_value" />
java代码如下
//在application应用<meta-data>元素。
ApplicationInfo appInfo = this.getPackageManager().getApplicationInfo(
getPackageName(), PackageManager.GET_META_DATA);
String msg = appInfo.metaData.getString("application_name");
3.4 在receiver中,也就是广播接收者(拨打电话的时候会看到toast消息)
xml中配置如下
<receiver android:name=".MyReceiver">
<meta-data android:name="receiver_name" android:value="receiver_value" />
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
java代码如下
//在receiver应用<meta-data>元素。
if (TextUtils.equals("android.intent.action.PHONE_STATE", intent
.getAction())) {
ComponentName cn = new ComponentName(context, MyReceiver.class);
try {
ActivityInfo info = context.getPackageManager().getReceiverInfo(cn,
PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
String msg = info.metaData.getString("receiver_name");
// 打电话测试即可
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
Logcat输出信息
11:11:46.733: V/MainActivity(571): application meta data value:application_meta_data_value
11:11:46.733: V/MainActivity(571): activity meta data value:activity_meta_data_value
11:11:46.763: V/MainActivity(571): service meta data value:service_meta_data_value
11:11:46.783: V/MainActivity(571): receiver meta data value:receiver_meta_data_value