Android系统资源

Android系统资源加载

前言

在开发 APP 的时候,会在 res/ 下引入众多资源,但是有些资源是不需要引入的,因为 Android 系统已经提供了这些资源。所谓 Android 系统资源,就是 Android 系统自带的,可以供所有 APP 使用的资源。比如像 YES/NO 这种简单的字符串,可以直接引用 Android 系统自带的资源。

使用 Android 系统资源的好处:

  1. 减少开发成本。如对于国际化的 APP,往往需要翻译全球多种语言。引用 Android 资源,可减少翻译的成本。
  2. 减少设计成本。如 Android 资源提供了很多图像等资源,直接使用这些资源,可以省去设计图像、动画、颜色等的成本。
  3. 与系统风格保持一致。如 Android 系统的资源往往应用到系统主题等等,引用 Android 资源可以更好的保持 Android 倡导的设计。
  4. 读取系统配置。某些 Android 资源是 Android 系统功能的配置资源,如当前设备是否支持通话能力。

Android系统资源概述

一般情况下,Android 系统资源在 AOSP 的路径是:

frameworks/base/core/res/

一般情况下,Android 资源放置手机的位置是:

/system/framework/framework-res.apk

一般情况下,Android 资源在 SDK 中的路径是:

android-sdk/platforms/android-xx/data/res/

如:android-sdk/platforms/android-26/data/res/

Android系统资源权限分类

Android 系统资源分两种:

  1. 公开。即全局公开性,所有 APP 可便捷应用。
  2. 非公开。Android 系统对这些资源进行了一定性的隐藏,意在这些资源提供给Android系统工程所引用。但是 Android 不禁止 APP 去使用这些资源。

Android加载资源简介

关系类图

资源架构类图

时序图

加载资源流程

一般情况,一个 APP 可以加载 APP 本身打包编译的资源,可以加载 Android 系统资源,可以加载 APP overlay 资源。Android 系统是如何保证资源加载的准确性和安全性呢?在 Android 资源加载中,有一个资源路径概念,APP 只能加载资源路径下的资源。

如果确定资源路径?

资源加载从上下文 Context 开始,因此路径的设定也从 Context 的创建过程中进行设定。在创建 Context 的过程中,会创建 Resources 对象(创建Activity Context为例)。如下:

public @Nullable Resources createBaseActivityResources(@Nullable IBinder activityToken,
    @Nullable String resDir,。  //资源路径,一般为 APP 的资源,即 APP 安装路径
    @Nullable String[] splitResDirs,  //分离 APK 资源路径,现在的Android版本一般都不需要这个了
    @Nullable String[] overlayDirs,  //overlay资源路径,
    @Nullable String[] libDirs,
    .....) {
    try {
        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");
        final ResourcesKey key = new ResourcesKey(
                resDir,
                splitResDirs,
                overlayDirs,
                libDirs,.....);
        classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
        //创建 Resources 对象
        return getOrCreateResources(activityToken, key, classLoader);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
    }
}

这个方法定义在文件 frameworks/base/core/java/android/app/ResourcesManager.java 中。

请看上面代码中的注释。这里再看看 Resources 的创建过程,看看资源的路径是如何设定。

创建Activity Context过程

请特别注意上图中红色注释部分。

在上图中的 addAssetPath() 方法中,设置了 resDir、Split apk dir、overlayDir。但是没有设定 framework 的资源的,即 Android系统资源。可见,Android系统资源的路径并不在这里进行设定。由于 Android系统资源是面向所有 APP 的,因此每个 APP 都需要统一设定相同的路径,因此它的设定路径稍微有点不同。

设定 Android 系统资源路径

在上图中,在 createAssetManager() 方法中会创建 AssetManager 实例,在实例化过程中会设定 Android 系统资源路径。如下图:

设定系统资源路径

请特别注意上图中红色注释部分。

引用Android资源

在上面的章节Android加载资源简介中对 Android 资源的加载有了初步的认识,下面继续学习如何引用 Android 资源。

引用公开资源

Java代码中引用

String str = getResources().getString(android.R.string.yes);

xml代码中引用

android:text="@android:string/yes"

引用非公开资源

Java代码中引用

//params: 
// 1:res name
// 2:res type(string、bool、drawalbe...)
// 3:package(Android资源APK的包名为android)
int resId = getResources().getIdentifier("config_showNavigationBar", "bool", "android");
boolean isShowNav = getResources().getBoolean(resId);

在AOSP的源码中可以直接通过如下方式引用:

boolean isShowNav = getResources().getBoolean(com.android.internal.R.bool.config_showNavigationBar);

在APP工程使用这种方式会编译报错。

但是,不管是AOSP还是APP工程中,都不推荐第二种方式,因为有些厂商会对AOSP中的资源进行修改,此时 Android 资源的 res id 已经产生移位,当你用 SDK 中的 res id 去引用不同厂商的手机的 Android 资源时,可能会发生异常或者返回的结果并不是正确的结果。通过第一种方式,先获取 res id,然后再通过 res id 去获取资源,可以有效规避 res id 移位的问题。

xml代码中引用

android:enabled="@*android:bool/config_voice_capable"

在 xml 中引用 Android 系统非公开资源时,IDE 工具不会给你“代码提示”,因此需要你手动写完。且xml文件中会高亮标红,表示找不到该资源,但是不需要关心它,你可以正常编译和使用。xml中引用无法规避 res id 移位的问题

总结

在本文中学习中,学习了什么是 Android 系统资源,Android APP 加载资源的过程,APP 资源路径的确定过程,以及在 Java 和 xml 中如何引用 Android 系统资源。你可以在你的 Android SDK 目录中查看 Android 自带了那些资源,具体路径请查看第二章节Android系统资源概述。程序员不重复造轮子,能引用 Android 自带资源就用 Android 自带资源吧。

关注微信公众号,获取更多实时动态


扫一扫关注微信公众号

我的Blog:http://blog.csdn.net/myfriend0/