使用 switch 语句的的时候,需要注意 case 分支后的引用在 Project 和 Library 下的区别。因为在 Library 中可能存在资源无法被引用的情形。在继续阐述之前,先看一段代码:
1 | public EditorViewHolder onCreateViewHolder(View itemView, int itemLayout, EditorAdapter adapter) { |
这段代码在 Project 中不会有任何报错和提示,但是在 Library 中会如下报错:
Constant expression required
----------------------------------------------------------------------------------------------
Resource IDs cannot be used in a switch statement in Android library modules less... (Ctrl+F1)
Validates using resource IDs in a switch statement in Android library module.
Resource IDs are non final in the library projects since SDK tools r14, means that the library code cannot treat these IDs as constants.
需要常量表达式
----------------------------------------------------------------------------------------------
资源 ID 不能在 Android 库模块的 switch 语句中使用 折叠... (Ctrl+F1)
对 Android 库模块中 switch 语句使用的资源 ID 进行验证。
从 SDK tools r14 开始,资源 ID 在库项目中是没有被 final 修饰的,这意味着库代码不能将这些 ID 视为常量。
这个错误提示基本表述清楚了原因。首先,case 分支后面的参数必须是常量表达式;其次,如果在 Android 库的 switch 语句中使用了资源 ID,那么系统会对这些 ID 进行验证;最后,从 SDK tools r14 开始,资源 ID 在 Library 中就不被 final 修饰,那么这些 ID 就不能被当作常量。那么,事实果然是这样吗?将文章开头处的代码块分别放至 Library 和 Project 中进行编译,编译结束后分别查看 Library 和 Project 的 R 文件。结果如下:
1 | // Library 中 R 文件的 layout 引用 |
1 | // Project 中 R 文件的 layout 引用 |
查看相应的 R 文件,我们会发现 Project 中的资源 ID 果然比 Library 中多一个 final 修饰符,这就解释了为什么同样的代码在 Library 中报错,而在 Project 中能编译和运行。因为 Project 中被 final 修饰的资源 ID 可以被当成常量。那么,如果仍然要在 Library 中使用资源 ID 进行逻辑处理,应该怎么办呢?我们可以使用 if else 语句,代码如下:
1 | public EditorViewHolder onCreateViewHolder(View itemView, int itemLayout, EditorAdapter adapter) { |
问题到这里就解决了。新的问题来了,Google 究竟是出于什么原因对资源 ID 的修饰进行改变的呢?经过一番查找,终于在 Build changes in revision 14 中找到了原因:
In order to implement this, we had to change the way resource IDs are generated. In a regular projects, resource IDs are generated as final static int. These constants then get inlined into the classes that use them. This means the compiled classes do not access the values stored in, say, R.layout.myui, but instead directly embed the value 0x000042.
To make the compiled classes not embed this value and instead access it from the R classes, library project will generate the resources IDs as static int only.
The resource IDs will still be generated as final static int in the final R class generated in the main project with the resources of the main projects and all required libraries.
Warning: Generating IDs as non final in the library projects, means that the library code cannot treat these IDs as constants. This means, for example, that you can’t use res IDs in a switch statement.