Skip to content

Android - 资源

构建健壮的 Android 应用不仅仅是编写 Kotlin 或 Java 代码。你还需要管理代码使用的各种静态资源,例如图像、颜色、布局定义、用户界面字符串、动画、字体等。这些资源被保存在项目 res/ 目录下的独立子目录中。

本教程将指导你如何组织应用程序资源,为不同的设备配置指定备选资源,以及如何在现代 Android 应用中高效地访问它们。

Android Studio 中典型的 Android 项目结构组织资源如下:

MyProject/
app/
src/
main/
AndroidManifest.xml
java/
com/example/myproject/
MyActivity.java
res/
animator/ (属性动画的 XML 文件,例如 objectAnimator)
anim/ (旧式补间动画的 XML 文件 - 现在不太常用)
color/ (定义状态列表颜色的 XML 文件)
drawable/ (位图文件:.png, .jpg, .gif;形状、矢量图、状态列表的 XML 文件)
font/ (字体文件:.ttf, .otf,或定义字体家族的 XML 文件)
layout/ (定义 UI 布局的 XML 文件)
menu/ (选项菜单、上下文菜单的 XML 文件)
mipmap/ (特定密度启动器图标:icon.png)
navigation/ (Jetpack Navigation 导航图的 XML 文件)
raw/ (以原始形式保存的任意文件)
values/ (简单值的 XML 文件:strings.xml, colors.xml, dimens.xml, styles.xml, themes.xml)
xml/ (任意 XML 配置文件)

以下是常见资源目录及其类型的细分:

编号目录 & 资源类型
1animator/
定义属性动画的 XML 文件(例如,使用 <objectAnimator>、<valueAnimator>)。保存在 res/animator/ 中,通过 R.animator 访问。
2anim/
定义旧式补间动画的 XML 文件。保存在 res/anim/ 中,通过 R.anim 访问。通常更偏好 animator/ 中的属性动画,因为它更灵活。
3color/
定义颜色状态列表(例如,用于按钮状态)或简单颜色资源的 XML 文件。保存在 res/color/ 中,通过 R.color 访问。
4drawable/
图像文件(例如,.png、.jpg、.webp)或编译为 drawable 资源的 XML 文件(例如,形状、矢量图、状态列表 drawable、渐变)。保存在 res/drawable/ 中,通过 R.drawable 访问。强烈推荐使用矢量图来获得与分辨率无关的图形。
5font/
字体文件(例如,.ttf、.otf)或定义字体家族的 XML 文件。保存在 res/font/ 中,通过 R.font 访问。
6layout/
定义用户界面结构的 XML 文件(例如,用于 Activity 或 Fragment)。保存在 res/layout/ 中,通过 R.layout 访问。
7menu/
定义应用菜单的 XML 文件(例如,选项菜单、上下文菜单)。保存在 res/menu/ 中,通过 R.menu 访问。
8mipmap/
主要用于特定密度的应用启动器图标。Android 系统使用这些图标为设备屏幕选择最佳分辨率图标。通过 R.mipmap 访问。
9navigation/
使用 Jetpack Navigation 组件的应用定义导航图的 XML 文件。保存在 res/navigation/ 中,通过 R.navigation 访问。
10raw/
以原始形式保存的任意文件(例如,音频、视频文件)。使用 Resources.openRawResource() 和 R.raw.filename 访问。
11values/
包含简单值(如字符串、尺寸、颜色、样式和主题)的 XML 文件。常见文件名包括:
- strings.xml: 字符串值 (R.string)。
- colors.xml: 颜色定义 (R.color)。
- dimens.xml: 尺寸值 (R.dimen)。
- styles.xml: UI 样式 (R.style)。
- themes.xml: 应用或 Activity 主题(对于 Material Design 3,通常位于 res/values/themes/ 和 res/values-night/themes/ 中)。
- arrays.xml: 资源数组 (R.array)。
- attrs.xml: 自定义视图的自定义属性。
12xml/
可在运行时使用 Resources.getXml() 读取的任意 XML 文件。对于配置数据非常有用。

现代 Android 应用必须适应各种各样的设备。你应该提供备选资源来支持特定的设备配置,例如不同的屏幕尺寸、密度、方向、语言和 UI 模式(如深色主题)。

要指定特定于配置的备选资源:

  • 在 res/ 中创建一个名为 <资源名称>-<配置限定符> 的新目录。例如,对于最小宽度为 600dp 的屏幕,使用 layout-sw600dp 作为布局,或者对于西班牙语字符串使用 values-es。
  • <资源名称> 是标准资源类型(例如,drawable、layout、values)。
  • <配置限定符> 指定配置(例如,land 代表横向,hdpi 代表高密度,night 代表夜间模式)。你可以组合多个限定符(例如,drawable-en-land-hdpi)。
  • 将备选资源文件保存在此新目录中。这些文件必须与默认资源文件具有完全相同的名称。Android 会在运行时根据当前设备配置自动加载适当的资源。

示例:为不同屏幕密度提供不同的 drawable 资源,并提供矢量图作为默认(或适用于所有密度,如果设计允许):

MyProject/
app/src/main/
res/
drawable/ (默认,通常用于矢量图或 -nodpi 资源)
icon.xml (矢量图)
background.png
drawable-mdpi/ (中等密度 ~160dpi)
background.png
drawable-hdpi/ (高密度 ~240dpi)
background.png
drawable-xhdpi/ (超高密度 ~320dpi)
background.png
drawable-xxhdpi/ (超超高密度 ~480dpi)
background.png
drawable-xxxhdpi/ (超超超高密度 ~640dpi)
background.png
mipmap-anydpi-v26/ (用于自适应图标)
ic_launcher.xml
mipmap-hdpi/
ic_launcher.png (遗留启动器图标)
...

提示:对于大多数图标和简单图形,使用矢量图(drawable/ 目录中的 .xml 文件)。它们可以无损缩放并减小 APK 大小。对于启动器图标,使用自适应图标,并在 mipmap 目录中提供遗留版本。

示例:为纵向和横向提供不同的布局,以及为英语(默认)和阿拉伯语提供不同的字符串:

MyProject/
app/src/main/
res/
layout/ (默认布局 - 通常为纵向)
activity_main.xml
layout-land/ (横向布局)
activity_main.xml
values/ (默认字符串 - 通常为英语)
strings.xml
values-ar/ (阿拉伯语字符串)
strings.xml (如果在 Manifest 中设置了 android:supportsRtl="true",则自动支持从右到左的布局)

常用限定符包括:语言和区域(-en、-fr-rCA)、最小宽度(-sw<N>dp)、可用宽度/高度(-w<N>dp、-h<N>dp)、屏幕方向(-land、-port)、UI 模式(-night、-car)、API 级别(-v21)。请参考官方 Android 文档,获取完整的限定符列表和提供备选资源的最佳实践。

你需要在 Kotlin/Java 代码或 XML 文件中访问定义的资源。

编译 Android 应用时,会生成一个 R 类。此类包含项目中 res/ 目录下所有资源的静态整数 ID。你使用这些 ID 来访问资源。

示例:在 Activity 中为 ImageView 设置图像并为 TextView 设置文本(使用 View Binding,这是与视图交互的推荐方式):

首先,在你的模块级 build.gradle.kts(或 build.gradle)文件中启用 View Binding:

// build.gradle.kts (Groovy: buildFeatures { viewBinding true })
android {
// ...
buildFeatures {
viewBinding = true
}
}

然后,在你的 Activity(例如,MyActivity.java)中:

package com.example.myproject;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
// 假设你的布局文件是 activity_my.xml,则会生成此类
import com.example.myproject.databinding.ActivityMyBinding;
public class MyActivity extends AppCompatActivity {
private ActivityMyBinding binding; // ViewBinding 对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 膨胀布局并获取绑定对象
binding = ActivityMyBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// 使用绑定对象访问视图(例如,如果你有一个 id 为 'myImageView' 的 ImageView)
// binding.myImageView.setImageResource(R.drawable.my_image_name);
// 原始上下文示例:假设有一个 id 为 'myImageViewInXml' 的 ImageView
binding.myImageViewInXml.setImageResource(R.drawable.myimage); // R.drawable.myimage 指代 res/drawable/myimage.png (或 .xml)
// 假设有一个 id 为 'messageTextViewInXml' 的 TextView
binding.messageTextViewInXml.setText(R.string.hello_message); // R.string.hello_message 指代 strings.xml 中的一个字符串
// 获取颜色资源(例如,来自 res/values/colors.xml):
// int myColor = ContextCompat.getColor(this, R.color.my_custom_color);
// binding.messageTextViewInXml.setTextColor(myColor);
}
}

在此示例中,R.drawable.myimage 指代位于 res/drawable* 目录中的图像文件(例如,myimage.png 或 myimage.xml)。R.string.hello_message 指代在 res/values/strings.xml 中定义的名为 hello_message 的字符串资源。

示例:包含 hello_message 的 res/values/strings.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">My Application</string>
<string name="hello_message">Hello from Resources!</string>
</resources>

示例:在 Activity 的 onCreate() 方法中加载布局:

public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 这会加载 res/layout/activity_main.xml 中定义的布局
setContentView(R.layout.activity_main);
}
}

你还可以使用 @ 符号直接在 XML 文件中(例如,布局、样式、drawable)引用资源。

语法:@<包名>:<资源类型>/<资源名称>

  • 如果资源来自你自己的应用,则 <包名> 是可选的(通常省略)。
  • <资源类型> 是 R 的子类(例如,string、drawable、color、dimen)。
  • <资源名称> 是资源文件的名称(不带扩展名)或 XML 资源文件中的 name 属性值。

示例:res/values/colors.xml 和 res/values/strings.xml:

res/values/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="app_primary_color">#FF6200EE</color>
<color name="text_error_red">#B00020</color>
</resources>
<!-- res/values/strings.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="greeting">Hello World!</string>
<string name="submit_button_text">Submit</string>
</resources>

示例:在布局文件(例如,res/layout/activity_main.xml)中使用这些资源:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="@dimen/activity_padding"> <!-- 假设 @dimen/activity_padding 在 dimens.xml 中 -->
<TextView
android:id="@+id/greetingTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/greeting"
android:textColor="@color/app_primary_color"
android:textSize="@dimen/text_size_large" /> <!-- 假设 @dimen/text_size_large 在 dimens.xml 中 -->
<Button
android:id="@+id/submitButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/submit_button_text"
android:backgroundTint="@color/app_primary_color" />
</LinearLayout>

注意使用 ?attr/ 来引用主题属性(例如,android:textColor="?attr/colorPrimary"),这是创建可主题化 UI 的强大方法。当颜色应适应应用主题时,这比直接硬编码颜色更可取。

理解如何组织和访问资源对于 Android 开发至关重要,使你能够创建灵活、可维护和适应性强的应用程序。