Resource,即资源,在Android中,资源是指代码中使用附加文件和静态内容,例如位图、界面布局、界面字符串、动画说明等等。html
咱们将资源放在分类目录下,以便单独对其进行维护,例如图像和代码中的字符串。此外,还应为特定设备提供备用资源,例如根据屏幕尺寸提供不一样界面布局,或者根据语言设置提供不一样的字符串,java
各类类型的资源被放入项目res/
目录的特定子目录中。以下所示为一个简单项目的文件层次结构。android
注意:切勿将资源文件直接保存在 res/ 目录内,由于这样会形成编译错误,应按类别新建子目录。
MyProject/ src/ MyActivity.java res/ drawable/ graphic.png layout/ main.xml info.xml mipmap/ icon.png values/ strings.xml
Android支持的分组资源类型请参考官方文档:分组资源类型json
之因此提供备用资源,是为了支持特定的设备配置。如针对不一样的屏幕密度和语言,应分别加入备用的可绘制对象资源和备用字符串资源。在运行时,Android会检测当前设备配置并为应用加载合适的资源。
格式:在res/
目录下建立以<resources_name>-<config_qualifier>
形式命名的新目录app
举例:以下所示为备用的可绘制对象资源:
更多有关可绘制对象资源类型请参考下图:ide
更多配置限定符的内容请参考官方文档 提供备用资源,以及关于建立别名资源的方法请参考 建立别名资源。
编译应用时,aapt会生成R类,其中包含res/目录下全部资源的资源ID,每种资源类型都有对应的R子类,而且该类型下的每一个资源都有静态的整型数——资源ID。因而,咱们能够在项目中借助R
类中生成的资源ID来访问这些资源。例如R.drawable对应于全部可绘制对象资源,引用方式为R.drawable.icon。布局
格式:[<package_name>.]R.<resource_type>.<resource_name>
测试
说明:动画
<package_name>
:是资源所在包的名称,若是引用的资源是本身的提供的资源,则不须要;<resource_type>
:是资源类型的R
子类;<resource_name>
:是不带扩展名的资源文件名。注意资源名称是不包含扩展名的,例如引用图片时没有必要加上.jpg
或者.png
等。
举例:R.drawable.myimage
、R.string.main_title
、R.layout.main_screen
等。ui
格式:@[<package_name>:]<resource_type>/<resource_name>
说明(同上):
<package_name>
:是资源所在包的名称,若是引用的资源是本身的提供的资源,则不须要;<resource_type>
:是资源类型的R
子类;<resource_name>
:是不带扩展名的资源文件名。举例:@color/opaque_red、@string/hello
如要引用系统资源,则您须要加入包名称。例如:
android:textColor="@android:color/secondary_text_dark"
。因为系统资源分为public和非public,public的声明是在<sdk_path>\platforms\android-版本号\data\res\values\public.xml
,而@*
表明引用系统的非public资源。格式:
@*android:<resource_type>/<resource_name>
,能够调用系统定义的全部资源,而上面的
@android:<resource_type>/<resource_name>
,则只可以调用public属性的资源。
例如将 Android 提供的布局资源用于 ListAdapter 中的列表项:setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myarray));
,其中,simple_list_item_1
是平台为 ListView 中的项目所定义的布局资源,便可以使用该资源,而没必要自行建立列表项布局。
样式属性资源容许你在当前应用的主题中引用属性的值。 引用样式属性,能够经过对UI元素进行样式设置以匹配当前主题提供的标准变体来自定义UI元素的外观,而不是提供硬编码的值(即具体的值)。 引用样式属性本质上说:“在当前主题中使用此属性定义的样式。”
格式:?[<package_name>:][<resource_type>/]<resource_name>
举例1,在xml文件中引用主题属性:
<EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="?android:textColorSecondary" android:text="@string/hello_world" />
<!-- Secondary text color. --> <attr name="textColorSecondary" format="reference|color" />
在以上代码中,是将android:textColor属性指定为当前主题背景中某个样式属性的名称,即将android:textColorSecondary
样式属性的值用做此控件textColor
的值。
显示声明的格式为:
?android:attr/textColorSecondary
,可是这里无须显示声明。
举例2,在style文件中引用主题属性:
<style name="Widget.CompoundButton"> <item name="focusable">true</item> <item name="clickable">true</item> <item name="textAppearance">?attr/textAppearance</item> <item name="textColor">?attr/textColorPrimaryDisableOnly</item> <item name="gravity">center_vertical|start</item> </style>
若咱们要访问原始文件,则不该该将文件放于res/
目录下,由于从res/
读取资源的惟一方法是使用资源 ID,所以,咱们能够将资源保存在assets/
目录中。
而访问的方式则须要利用AssetManager读取原始数据。以下所示
StringBuilder stringBuilder = new StringBuilder(); try { AssetManager assetManager = context.getAssets(); BufferedReader bf = new BufferedReader(new InputStreamReader( assetManager.open(file.json))); String line; while ((line = bf.readLine()) != null) { stringBuilder.append(line); } } catch (IOException e) { e.printStackTrace(); }
但如果只须要读取原始数据的能力,例如读取视频文件或音频文件,则可将文件保存在res/raw/
目录中,并利用openRawResource()
读取字节流。如:mMediaPlayer = MediaPlayer.create(this, R.raw.song);
。
经过上面讲解能够知道@
是引用的意思,那么+
呢?+
表示在R.java
中名为type的内部类中添加一条记录。举个例子:android:id="@+id/submit_btn"
表示新建一个名为submit_btn
资源id。上面的例子就是最多见的用法,即定于控件id。
@+id/ID名称
:表示新建一个资源ID;
@id/ID名称
:引用已定义的资源ID,包括系统ID;
@android:id/ID名称
:引用系统ID,其等效于@+id/ID名称
。
如何根据文件名来获得资源ID,这就要借助Resources的getIdentifier方法了。以下代码所示:
Resources res = getResources(); final String packageName = getPackageName(); //方法1 测试1 int imageResId = res.getIdentifier("ic_launcher", "mipmap", packageName); //方法2 测试1 int imageResId2 = res.getIdentifier(packageName + ":mipmap/ic_launcher", null, null); //测试2 int musicResId=res.getIdentifier("song", "raw", packageName); //测试3 int notFoundResId=res.getIdentifier("activity_main", "drawable", packageName); Log.d("TAG", "imageResId: " + imageResId + ";imageResId2: " + imageResId2 + ";musicResId: " + musicResId + ";notFoundResId: " + notFoundResId);
运行结果:
imageResId: 2131361792;imageResId2: 2131361792;musicResId: 2131427328;notFoundResId: 0
看看源码中getIdentifier方法实现:
/** * Return a resource identifier for the given resource name. A fully * qualified resource name is of the form "package:type/entry". The first * two components (package and type) are optional if defType and * defPackage, respectively, are specified here. * * <p>Note: use of this function is discouraged. It is much more * efficient to retrieve resources by identifier than by name. * * @param name The name of the desired resource. * @param defType Optional default resource type to find, if "type/" is * not included in the name. Can be null to require an * explicit type. * @param defPackage Optional default package to find, if "package:" is * not included in the name. Can be null to require an * explicit package. * * @return int The associated resource identifier. Returns 0 if no such * resource was found. (0 is not a valid resource ID.) */ public int getIdentifier(String name, String defType, String defPackage) { return mResourcesImpl.getIdentifier(name, defType, defPackage); }
注释内容要点以下:
package:type/entry
,若是资源名这个参数有完整地指定,后面的defType和defPackage能够省略,如上面代码中res.getIdentifier(packageName + ":drawable/ic_launcher", null, null);
的形式;AssetManager.class
中的native
方法int getIdentifier(String name, String defType, String defPackage) { if (name == null) { throw new NullPointerException("name is null"); } try { return Integer.parseInt(name); } catch (Exception e) { // Ignore } return mAssets.getResourceIdentifier(name, defType, defPackage); }
/** * Retrieve the resource identifier for the given resource name. */ /*package*/ native final int getResourceIdentifier(String type, String name, String defPackage);
参考资料: