Android编译资源 - resources.arsc

Ziv*_*gic 28 resources android r.java-file

我想弄清楚"编译资源"是什么意思.

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

我已经阅读了很多关于这个主题的文章,但没有找到一个简单的答案.我读过的最好的是:android资源和资源ID之间的映射如何工作的?.

我怎么理解:

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

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

一个例子:

所以要简单一点:假设我在activity_main.xml中有这个:

    <TextView android:id="@+id/my_textView"
        android:text="@string/hello_world" 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
Run Code Online (Sandbox Code Playgroud)

我从我的onCreate中调用它:

findViewById(R.id.my_textView)
Run Code Online (Sandbox Code Playgroud)

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

public static final int my_textView=0x7f08003f;
Run Code Online (Sandbox Code Playgroud)

在生成的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号码?(它是否应该表示稍后将映射到将存储对象的物理内存的值?)

pel*_*ide 27

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节点(例如LinearLayout,RelativeLayout等)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节点(例如LinearLayout,RelativeLayout等),它们的属性(例如android:layout_width),资源id的.这些资源id引用了apk文件中的真实资源.属性在运行时解析为值.对于任何重定向(@dimen/...与之相反4dp@color/...相反"#FFaabbcc"),解析过程都是明智的,并返回可用值(dimen值的解析方式与color值不同).

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

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

例如,对于包含的布局RelativeLayout,inflater将打包layout_width并将layout_heightAttributeSet传递给构造函数 RelativeLayout(Context context,AttributeSet attrs,int defStyleAttr,int defStyleRes).在这种情况下,一些属性及其值由RelativeLayout.initFromAttributes()解析,其余属性由父ViewGroup.initFromAttributes()解析.

android:id视图只是另一个属性.inflater通过在实例化后调用setId(id)该视图来存储每个视图的id

现在回答你的问题 R.id是java数组,并且my_textview是该数组中的整数.该id视图的 my_textview是该整数(与0x7F的开始).该方法findViewById()对该视图层次结构进行深度优先搜索以查找相应的视图.

希望这可以帮助.您在问题中提供的链接已经回答了如何通过aapt生成ID.

它是一个很好的系统,可以管理具有多种变化的设备的资源.而且,实施真的很快!! 以此为基础,它允许实现更高级别的功能(例如,运行时资源覆盖)

  • 多么棒的答案。你是安卓系统吗? (4认同)