美文网首页
R文件与switch-case表达式的恩怨

R文件与switch-case表达式的恩怨

作者: 清明捉鬼 | 来源:发表于2019-07-25 21:20 被阅读0次

    前言

    很久之前在打包aar时遇到资源文件switch-case语句报错问题,按alt+enter IDE直接给我转if- else,今天写代码时想到有钱人的特权时突然联想到这个问题,于是搜集一番,整理成简短文。

    题为——R文件与switch-case表达式的恩怨。

    R文件

    • R文件的由来(本人的看法)
      Android工程中包含大量资源与数值文件,其若要被访问,按照语言的写法就必须读取本地文件,对比id字段名获取值内容,与游戏读取本地数值一样非常耗时,而且这也将对android开发过程极大复杂化,so官方为开发者提供了解决方案,便是在编译打包阶段将其读取生成一个id(其读取过程虽然耗时但是其发生在编译打包期间所以不会影响用户使用),形成一个字典,转为成类,装在一个叫R的总类里面,通过id能够直接获取到对应内容(其中这个id值为16进制,所以我怀疑这个id是地址值或者是为了区分键值 eg:activity_main对应id 0x1234567,id对应具体值为1234567 ),所以这个id最好为常量,不要轻易更改。
      tips:R文件报错(生成失败)必然发生资源文件字典生成违背官方方案的事件,即我们通常所说的资源文件报错,so we need to排查所有的资源文件,涉及文件参考下面R的内部类

    • R的内部类
      R.anim
      R.animator
      R.array
      R.attr
      R.bool
      R.color
      R.dimen
      R.drawable
      R.fraction
      R.id
      R.integer
      R.interpolator
      R.layout
      R.menu
      R.mipmap
      R.plurals
      R.raw
      R.string
      R.style
      R.styleable
      R.transition
      R.xml

    R文件对子模块与主工程的影响

    Tips:
    下文的 子模块 即为 Library , 主工程 可以理解为 父模块,key 可以理解为R文件中id的字段名
    1.switch-case 中的 case 表达式,必须使用常量或者直接使用具体值
    2.R文件生成的最终值必须要求在一个分配体系中,否则容易出现多key一值

    • 为什么子模块资源引用不能使用switch-case 表达式?
      因为子模块中R文件的所有id值没有用final修饰,其不是常量或具体值,主工程R文件的id其实是一个个常量值。
    • 为什么Library的R文件生成的不是常量?
      这一切源于ADT14对于编译的更改即4.0时编译工具的更改。在ADT14编译工具未修改前,子模块每次编译的R文件都会生成最终静态常量值,为了防止多key一值等错误发生(错误原因如下举例),每次不得不将主工程与子模块一起重新编译(此时子模块打包的R文件所有值将无效被重新编译分配),同一次编译不会发生分配相多个字段名对应一个值的情况,so那时library的R文件与父模块R文件相安无事,但是ADT14后为加快编译速度,决定子模块打包后不参与主工程的编译,这问题就来了,于是其修改了子模块R文件的生成规则,子模块R文件生成的id值从此不是静态常量而是静态变量,在主工程编译时两处使用同一生成体系生成或者修改,以避免发生错误。
    • 多key一值错误举例
      观下表值为0x7f010001的id key名,其在Library独立编译时对应的key为colorAccent2,但是在主工程里key为colorAccent,如果Library是最终值无法被更改,又不参与主工程重新进行编译分配id,那么colorAccent2、colorAccent这个两个key获取的id值就相同皆为0x7f010001,在同一工程里,程序还怎么玩,这是一个错误,所以这里其实可以得出一个原则,即R文件生成需要在一个分配体系下。
      原则:R文件生成需要在一个编译打包分配体系下
    • 最终合并生成
      在同一体系下子模块与主工程会先各自生成两个最终R文件,然后在最终打包apk时合并两R文件,其同一分配体系下merge发生冲突时一律采用主工程的值,与版本同步时的合并类似,Resource merging合并规则(说实话我并没有怎么看懂,还不如写demo实在),由于合并后同一个key采用的是主工程的值,所以子模块代码中的此key原资源指向失效全部指向主工程资源,子模块的资源指向全部作废,
      所以此处得出一个重要结论,这个结论在插件化时很受用,插件化时子模块资源起名建议加上前缀,譬如子模块工程名为DayTaskLib,xml资源名为daytasklib_mainactivity.xml
      结论1:子模块中与主工程的资源名一定不要重复,否则子模块的资源指向会失效,其会指向主工程对应key的资源
      结论2:所有子模块与主工程在打包后是公用一个R文件的。

    以color资源为例进行探究试验

    • Library color资源文件
    子模块 主工程
    作为依赖aar时主工程生成的LibraryR文件id image.png 单独生成aar时生成的R文件id image.png 示例color资源文件 image.png 主工程生成的R文件id image.png 示例color资源文件 image.png

    上表实验中我特意设置子模块 单独拥有colorAccents2颜色,主工程单独拥有colorPrimary2颜色
    可以从主工程生成的R文件中看出其包含了子模块的colorAccents2的id,但是子模块与主工程冲突的颜色id却只有主工程的,so我初步得出当两个R文件发生冲突时,其以主工程id为准的猜想,为了证明猜想正确,我在Library设置了两个图片

    9009142-155ed73479557cb7.png
    ,这两个图片的resourceId与主工程里的冲突,打包成apk运行后
    [图片上传中...(9009142-155ed73479557cb7.png-83f6df-1564056272492-0)]
    可以看出其代码没变,变的是指向id,所以结论正确。
    所以经工程测试试验对比发现,则其实可以得出结论子模块R文件与父工程R文件在打包时会发生内容merge,当两个id引用名冲突时,默认其值为父模块id值。
    上述表中子模块有两组R文件,分别是独立打包时生成的(生成的final修饰),另一个是作为依赖在主工程里打包生成(生成的final修饰)注意区分。

    相关文章

      网友评论

          本文标题:R文件与switch-case表达式的恩怨

          本文链接:https://www.haomeiwen.com/subject/orucrctx.html