Android编译资源 - resources.arsc

时间:2014-12-18 14:27:06

标签: android resources r.java-file

我想弄清楚“编译资源”是什么意思。

我为了解这个问题做了什么:

我读过很多关于这个主题的文章,但没有找到一个简单的答案。 我读过的最好的是:How does the mapping between android resources and resources ID work?

我的理解:

根据我的理解,当我们通过ANT(Eclipse)或Gradle(AS)编译项目时。 我们使用名为 aapt 的工具 - Android资产包装工具: 用于为我们的每个资源生成唯一ID,例如我们的布局,样式等,并将它们存储在查找表中。然后它通过生成两个文件来保留此查找表:

  1. 它生成具有这些唯一ID的R.java文件,因此我们将能够在编译期间使用我们的java代码中的资源。
  2. 它生成resources.arsc文件,该文件可以在资源* .ap_文件中找到。 这个resources.arsc文件稍后将由apktool打包到apk 此arsc文件格式是一种在运行时可由设备轻松映射和解析的格式。
  3. 一个例子:

    所以为了简单起见:假设我在activity_main.xml中有这个:

        <TextView android:id="@+id/my_textView"
            android:text="@string/hello_world" 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    

    我在onCreate中使用:

    来调用它
    findViewById(R.id.my_textView)
    

    在我的R.java文件中,我将看到:

    public static final int my_textView=0x7f08003f;
    

    在生成的apk上使用:aapt dump资源我可以看到它包含my_textView的两行: ec资源0x7f08003f com.example.lizi.liortest2:id / my_textView:flags = 0x00000000 资源0x7f08003f com.example.lizi.liortest2:id / my_textView:t = 0x12 d = 0x00000000(s = 0x0008 r = 0x00)

    我不明白:

    我原以为这个resources.arsc文件不仅包含资源ID,还包含我为视图定义的所有属性,例如android:layout_width =“wrap_content”。

    所以现在在运行时VM尝试运行findViewById(R.id.my_textView) 它如何知道要创建哪个视图/其属性?

    我根本无法理解它是如何工作的......这个查找表是否也不包含属性数据? 什么是0x7f08003f号码? (它是否应表示稍后将映射到将存储对象的物理内存的值?)

3 个答案:

答案 0 :(得分:24)

TL; DR :在android编译器(aapt)的帮助下,xml节点将被转换为Java类,并将相应的属性转换为数字ID。 Android运行时使用这些ID来实例化类以创建视图

答案很长

运行此命令以转储二进制文件xml aapt d xmltree apk_file_name res/layout/activity_main.xml aapt可在 android-sdk-dir / build-tools / 23.0.2 / aapt.exe 中找到)

这将显示xml节点(例如LinearLayoutRelativeLayout等)及其属性(例如android:layout_width, android:layout_height)及其值。请注意,可以在那里看到常量match_parent(数值0xffffffff-1)或wrap_content(数值0xfffffffe-2

事实上,您可以在apk中的任何其他xml文件上使用此命令,例如AndroidManifest.xml or layout files

apk文件只是一个zip存档,包含所有java类文件(classes.dex),所有已编译的资源文件和一个名为resources.arsc的文件。 此resource.arsc文件包含有关资源的所有元信息,xml节点(例如LinearLayoutRelativeLayout等),其属性(例如android:layout_width),资源id的。这些资源id指的是apk文件中的真实资源。属性在运行时解析为值。对于任何重定向(@dimen/...而不是4dp@color/...而不是"#FFaabbcc"),解决过程都很明智,并返回一个可用值({{1} }值的解析方式与dimen值不同。

什么是编译的XML文件: 已编译的XML文件与XML文件相同,资源引用已更改为其对应的color。例如,引用ids将替换为@string/ok。此外,0x7f000001命名空间中的属性更改为各自的整数值(例如android更改为wrap_content0xfffffffe

Android如何在运行时解析资源: 方法inflater.inflate()解析已编译的xml文件,并通过实例化xml节点来创建视图层次结构。每个xml节点都由java类实例化(例如LinearLayout.java,RelativeLayout.java)。要实例化,inflater会解析已编译的xml文件,收集节点的所有属性,并creates类型为AttributeSet的压缩结构。这个-2被传递给类构造函数。类构造函数负责遍历AttributeSet并解析每个属性值。

例如,对于包含AttributeSet的布局,RelativeLayout会将inflaterlayout_width打包到layout_height并将其传递给构造函数{{ 3}}。在这种情况下,某些属性及其值由RelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)解析,其余属性由父RelativeLayout.initFromAttributes()解析。

AttributeSet视图只是另一个属性。在实例化之后,inflater将ViewGroup.initFromAttributes()的每个视图的id存储在该视图上

现在回答您的问题 android:id是一个java数组,R.id是该数组中的整数。视图my_textview的{​​{1}}是此整数(以0x7f开头)。方法calling setId(id)在该视图层次结构上执行深度优先搜索,以查找相应的视图。

希望这会有所帮助。您在问题中提供的findViewById()已经回答了如何通过aapt生成ID。

这是一个管理多种维度设备资源的精彩系统。而且,实施真的很快!!以此为基础,它允许实现更高级别的功能(例如link

答案 1 :(得分:2)

LayoutInflater通过使用XML字符串来扩充视图。正如您在问题中提到的那样,XML字符串被编译到资源文件中。

请查看AOSP的以下代码段:

public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
    final Resources res = getContext().getResources();
    if (DEBUG) {
        Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                + Integer.toHexString(resource) + ")");
    }

    final XmlResourceParser parser = res.getLayout(resource);
    try {
        return inflate(parser, root, attachToRoot);
    } finally {
        parser.close();
    }
}

Resources.getLayout加载XML资源解析器

public XmlResourceParser getLayout(int id) throws NotFoundException {
    return loadXmlResourceParser(id, "layout");
}

XmlResourceParser loadXmlResourceParser(int id, String type)
        throws NotFoundException {
    synchronized (mAccessLock) {
        TypedValue value = mTmpValue;
        if (value == null) {
            mTmpValue = value = new TypedValue();
        }
        getValue(id, value, true);
        if (value.type == TypedValue.TYPE_STRING) {
            return loadXmlResourceParser(value.string.toString(), id,
                    value.assetCookie, type);
        }
        throw new NotFoundException(
                "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
                + Integer.toHexString(value.type) + " is not valid");
    }
}

getValue使用AssetManager&#39; getResourceValue,并调用loadResourceValue本机方法。此本机方法调用ResTable&n; getResource方法来获取存储在资源文件中的XML字符串。

答案 2 :(得分:0)

Use appt for android-sdk (ex:- /build-tools/27.0.3/aapt )

 run given script and get resources.arsc file content
./aapt dump resources ./debug.apk

Package Groups (1)
Package Group 0 id=0x7f packageCount=1 name=com.dianping.example.activity
  Package 0 id=0x7f name=com.dianping.example.activity
    type 1 configCount=3 entryCount=1
      spec resource 0x7f020000 com.example.activity:drawable/ic_launcher: flags=0x00000100
      config mdpi-v4:
        resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000000 (s=0x0008 r=0x00)
      config hdpi-v4:
        resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000001 (s=0x0008 r=0x00)
      config xhdpi-v4:
        resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000002 (s=0x0008 r=0x00)
    type 2 configCount=1 entryCount=1
      spec resource 0x7f030000 com.dianping.example.activity:string/app_name: flags=0x00000000
      config (default):
        resource 0x7f030000 com.dianping.example.activity:string/app_name: t=0x03 d=0x00000003 (s=0x0008 r=0x00)

此链接可能会帮助http://elinux.org/Android_aapt