上次我们问了每日一问 关于 R.java 的生成规则,你知道多少? ,但是一个有用的知识点还是没弄清楚。
对于不同的 module 下,同名但值不同的资源,最终:
- 会被覆盖成其中一个资源吗?
- 如果会,那么覆盖的规则是,随机吗?
更多问答 >>
-
2019-09-11 00:24
-
每日一问 gradle项目构建,需要经历哪些核心task,整个构建流程哪些我们可以干涉?
2019-09-15 23:29 -
2019-09-15 23:30
-
2019-09-17 22:41
-
2019-09-23 01:01
-
2019-09-04 23:33
-
2019-09-01 23:16
-
每日一问 Parcelable 为什么效率高于 Serializable ?
2019-08-26 00:02 -
每日一问 今天聊一下Gradle 相关,BuildConfig这个类是如何生成的?
2019-08-20 23:27 -
2019-08-18 21:42
测试了以下几种情况:
app中有test_value资源,依赖了同样有test_value资源的module1;
app中有test_value资源,依赖了同样有test_value资源的module1和module2;
app中无test_value资源,先后依赖了有test_value资源的module1和module2;
app中无test_value资源,先后依赖了有test_value资源的module2和module1;
打包后把apk拖进AS,点开
resources.arsc
文件,定位到test_value,会看到(下面4个结果分别对应上面的4种不同的做法):test_value的值是app中的值;
test_value的值是app中的值;
test_value的值是module1中的值;
test_value的值是module2中的值;
这也就对应了 @526227576 和 @cscxzxzc 同学所说规则:
如有同名资源,那么最终采纳的,app的优先级要高于module,而module之间的优先级则由app/build.gradle里面dependencies中的implementation顺序决定的。那它具体是怎么做到的呢?
源码分析:
按之前的方法打开ApplicationTaskManager的
createTasksForVariantScope
方法:可以看到,在生成资源值任务创建后,接着会创建一个叫合并资源的任务,一级级点进去:
来看看这个doFullTaskAction方法:
可以看到在执行到阶段2的时候,传进去的Lambda会调用ResourceMerger的
两个斜杠的英文注释是源码本身的注释:mergeData
方法,点进去(逻辑有点复杂,注意看注释):可以看到,它首先会遍历一个【装有全部资源名字的List】,并且在里面倒序遍历一个【装有全部资源的List】,然后逐个检查有没有跟外面遍历到的item同名,如果有的话,会用【它】所对应的值,替换掉【外面遍历到的item】所对应的值。
那这个【装有全部资源的List】是怎么来的?里面装的都是什么?可以先做个猜测:既然在mergeData方法中会倒序查找同名的资源,而在我们上面的测试中,app的优先级比module高,那么,这个list会不会就是【module2, module1, module0, app】这样排序的呢?如果是的话,就刚好能对应刚刚的测试结果。(篇幅原因,长话短说了)
回到MergeResources的doFullTaskAction方法中,会看到这一段代码(merger就是刚刚调用
mergeData
方法的ResourceMerger):可以看到,它是遍历了一个resourceSets,把全部元素都添加到了ResourceMerger(上面的mDataSets)中。
找到resourceSets,可以发现它是通过getResourcesComputer的compute方法获取的,看看:可以看到,在添加依赖库的资源时,是倒序遍历的,如果里面本来装的是【module0, module1, module2】,那么当遍历完成后,resourceSetList里面的元素就是【module2, module1, module0】,而最后,还添加了app中的资源集,但这时候没有指定索引,也就是添加到最后面了,
这样一来,也就对应了我们刚刚的猜测:app的资源集在resourceSetList的最后面,那么在合并资源时,倒序遍历的时候也就会先找到app里面的资源(如果有重名的话),其次是module0、 module1。。。。现在Gradle插件很多地方都改成了用Kotlin实现了,还没学习Kotlin的同学要赶紧学啦~
现在好多插件Kotlin还用不了...
那也要学
而module之间的优先级则由app/build.gradle里面dependencies中的implementation顺序决定的。优先使用前面的还是后面的哇? ...查看更多
而module之间的优先级则由app/build.gradle里面dependencies中的implementation顺序决定的。优先使用前面的还是后面的哇?
会优先采用前面的(如果有重名的话)
对于不同的 module 下,同名但值不同的资源,最终:
1.会覆盖成其中一个资源。2.不是随机的,他是根据相应的优先级进行资源合并的。https://developer.android.com/studio/write/add-resources.html
如果存在两个或两个以上的匹配版本的相同的资源,那么只有一个版本包含在最终的APK。构建工具选择哪个版本保持基于以下优先顺序(左边最高优先级):
build variant > build type > product flavor > main source set > library dependencies源集编译这也说明了优先级 https://developer.android.com/studio/build/build-variants.html#sourceset-build
我想请问一下,如果我有子module A和B 两个module下都定义了<string name="test">,那这个时候怎么确定合并后最终取的是哪个子module下的值? ...查看更多
我想请问一下,如果我有子module A和B 两个module下都定义了<string name="test">,那这个时候怎么确定合并后最终取的是哪个子module下的值?
如果优先级相同的话,好像会出现冲突错误的。(自己还没试过) 你可以看看这个(在最后一行):https://developer.android.com/studio/write/add-resource ...查看更多
如果优先级相同的话,好像会出现冲突错误的。(自己还没试过) 你可以看看这个(在最后一行):https://developer.android.com/studio/write/add-resources.html However, if your build configuration specifies multiple resource folders for a given source set and there are conflicts between those sources, an error occurs and the merge fails because each resource directory has the same priority.
1.不同模块下同名的资源文件一定会覆盖;
2.不是随机的。本人实际开发中真的遇到过,只要文件名相同,不管文件是SVG或PNG等等都会覆盖,至于覆盖规则应该是根据编译时module先后次序决定的。拿MVVM举例,Databinding在编译时不关在module中的/xxx/build/generated/source/kapt生成对应的java文件,App壳在/xxx/build/generated/source/kapt也会生成module中的java文件。如果使用ARouter,同样命名和文件,编译运行可能没问题,但是操作时会因找到文件与实践文件不一致而报错。cscxzxzc 童鞋提到的阿里Android开发手册中很有用处。补充下:一个App那么多模块,不可能你一个人开发,没有约束的话很容易重名(现实生活中就有那么多重名的,但xx省xx市xx大学xx班xx学号的小葱就一个)。所以尽量规范化命名。阿里的Android开发手册中就【推荐】模块化的开发要带模块前缀。
可以养成个习惯:
在 library 的 build.gradle 中添加 resourcePrefix , 则所有的资源须以 csc_ 开头。<在 library 的 build.gradle 中添加 resourcePrefix , 则所有的资源须以 csc_ 开头。> 并不能对xml文件做限制,如果能在git提交的时候做c ...查看更多
<在 library 的 build.gradle 中添加 resourcePrefix , 则所有的资源须以 csc_ 开头。> 并不能对xml文件做限制,如果能在git提交的时候做codereview就可以限制xml的命名规范
我说一种非常恶心的情况,你在app下写了一个资源test_string放在values下,用这个资源好好的,;然后你一来了一个模块也有资源test_string放在values下,然后values-zh也有,然后恭喜你,生气的事情发生了,现在你app下的test_string在中文下用的是模块在values-zh下写的了
你这种情况应该是 国际化产生的问题, 你把手机区域调到美国去应该就好了