"Resources$NotFoundException" 是什么意思?

7
我最近在这里发布了一个Resources$NotFoundException bug,并得到了通常的一些建议,例如删除"gen"文件夹、清理、刷新等等。SO和web上有数百(或数千?)名程序员遇到同样的异常并得到相同的建议。但我似乎找不到任何地方描述该错误真正的含义。

文档非常模糊:http://developer.android.com/reference/android/content/res/Resources.NotFoundException.html

Resources$NotFoundException是运行时错误,所以它可能在APK文件中查找某些东西。

  1. 资源如何在构建时构建到APK文件中?我们从XML文件开始,然后呢...?
  2. 运行时如何引用它们?
  3. 调试器中看到的资源ID与在APK文件中标识的方式之间的关系是什么?
  4. 哪些(Windows)工具可以用来检查APK文件以查找这些资源?

提前感谢您对这些问题的回答!

PS - 如果您认为您有答案原始bug,请在那里发帖,而不是在这个主题下;这是一个不同的问题。


通常这个错误意味着在构建系统上工作的Android团队认为他们解决了构建时间依赖问题,但未能做到,我们开发人员因此陷入了困境。 - satur9nine
2个回答

7
  1. 资源可以以各种方式打包,从原始资产到优化图像到打包的字节数据。所有这些都压缩成一个 apk 文件。资源的 id 是帮助找回它的关键。在开发过程中,构建工具 (aapt) 不断扫描 res 目录中的 xml、图像等,并在 R.java 中生成数字常量。有关 Android 构建过程的详细信息,请参阅此处

  2. 运行时,Resources 实例根据调用其哪个 get 方法来决定在哪里查找。数字 id 帮助它查询资源映射并找到正确的资源。实际数据加载由本地低级代码处理。

  3. 调试器可以显示对象及其字段。要找出缺少了什么,请读取 logcat 中的 NotFoundException 跟踪错误消息。它列出了资源 id 的十六进制值。

  4. ApkTool 可让您解压缩 apk 文件并重建 res 目录。

更新:

资源如何打包:

如果您有一个 apk 文件并想查看完整的资源表,请在 SDK 中运行 aapt 工具,例如:

 aapt list -v myApp.apk

它将显示以下细节:
Archive:  ./myApp.apk
 Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name
--------  ------  ------- -----  -------      ----  ----  ------    ----
     468  Deflate     228  51%         0  11-07-12 23:25  29fb0660  res/color/abs__primary_text_disable_only_holo_dark.xml
     468  Deflate     228  51%       332  11-07-12 23:25  bae4791a  res/color/abs__primary_text_disable_only_holo_light.xml
    2942  Stored     2942   0%    280417  10-27-12 16:52  9b5af43b  res/drawable-xhdpi/ic_mus.png
    2330  Stored     2330   0%    283418  10-27-12 16:52  21f5ba4d  res/drawable-xhdpi/ic_pic.png
    1556  Stored     1556   0%    285810  10-27-12 16:52  31c3402b  res/drawable-xhdpi/ic_vid.png

你可以在二进制数据中看到存储资源的方法(deflate、stored等)和偏移量,长度表示在偏移量之后读取多少字节才能获取该资源。
Resources.NotFoundException 打印什么信息:
下面是生成它的代码:
public void getValue(int id, TypedValue outValue, boolean resolveRefs)
        throws NotFoundException {
    boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
    if (found) {
        return;
    }
    throw new NotFoundException("Resource ID #0x"
                                + Integer.toHexString(id));
}

因此,它将打印出请求Resources实例加载的Id的十六进制值。

下面是R.java的一部分:

public static int absForceOverflow=0x7f010039;

你可以看到Id被分配了类似的十六进制值。
我能解决这个错误吗?
如果编译工具成功编译了您的项目,则不应首先出现此错误。除了清理或重新构建项目外,您无法做太多事情。这代表了构建工具或资源加载器中的错误或设备上apk的数据损坏。

要找出缺失什么,请阅读logcat中的NotFoundException跟踪错误消息。我该如何弄清这些消息的含义?例如,“05-21 12:47:00.060:W/ResourceType(4801):在包0中获取0x7f030006(t=2 e=6)的条目失败(错误-75)”。t和e是什么,错误-75是什么意思? - user316117
如果构建工具成功编译了您的项目,那么这个错误本来就不应该发生。但是,我们仍然可以在我们的崩溃分析系统中找到这个崩溃,只有很少一部分用户(可能是10000分之1)找不到这个资源,天知道发生了什么事情。 - Shaw

0
资源是如何在构建时打包到APK文件中的?我们从XML文件开始,然后呢...?
每当您在XML中使用@+id/,或将项目放置在strings.xml或drawable文件夹中时,编译器都会将/res文件夹中的所有资源转换为整数值,然后放入R.java中。
2. How are they referenced at runtime?

这些资源是通过在R.java中查找的整数值引用的。

3.调试器中看到的资源ID与APK文件中标识该资源的方式有什么关系?

根据我的理解,这个关系是在R.java中被建立起来的。

4.我可以使用哪些(Windows)工具来检查APK文件并找到这些资源?

不太确定...

这是我从自己的理解中收集到的所有信息。如果有任何错误的陈述,请指出来。


每当您在XML中使用@+id/、将项放置在strings.xml或者drawable文件夹中时,编译器将把该名称转换为整数值,然后将其放置到R.java中。但是R.java仅存在于构建时间而非运行时。它只有资源ID,没有实际的布局。那么,布局XML如何在APK文件中表示,这些资源ID又如何与APK文件中的布局信息相关联呢?请记住,运行时APK文件必须包含所有内容,因此诸如Resources$NotFoundException之类的运行时错误必须反映在APK文件中。 - user316117
一个 APK 只是一个花哨的 .zip 文件,所以我认为 R.java 充当了查找表。 - TronicZomB
这是一个合理的假设,但我需要摆脱假设来了解Resource$NotFoundException的真实含义;我们需要知道细节。是否有实际的查找表,如果有,它索引的是什么?“资源”是我们可能会想到的,但那意味着什么?Resource$NotFoundException是指在假定的表中没有条目,还是所索引的不是资源,或者不是正确类型的资源,或者其他什么原因? - user316117

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接