问题
this is an extension of Android: Why do we need to use R2 instead of R with butterknife? and Reference in R.java not final
I understand that fields of R.java in the library project do not have final modifier to protect value collisions between library projects. However ButterKnife recovers final modifier in R2 and uses it.
I think this goes to the collision problem and values can collide, but there is no problem. How does it work?
===
I add examples. There are one main project and one library project. The main project has com.main.R and the library project has com.library.R.
- When there is a collision:
- com.main.R: public static final int example = 0x1234
- com.library.R: public static int example = 0x1234
if build tools does not recompile the library project, how can we avoid the collision between those values?
- When ButterKnife creates R2
- com.main.R: public static final int example = 0x1234
- com.library.R: public static int example = 0x1234
- com.library.R2: public static final int example = 0x1234
com.library.R2 has a collision and even it has a final modifier. Doesn't it produce a problem? why?
Thanks
回答1:
Although final
keyword has been removed from the R.java
generated class since it caused a negative impact on the build performance, Butterknife uses only final
for itself which is why only the Butterknife code needs to be recompiled everytime a new id is to be added. The good point is Butterknife uses annotations in order to make sure that type that we return is always correct.
From the doc:
In other words, the constants are not final in a library project. The reason for this is simple: When multiple library projects are combined, the actual values of the fields (which must be unique) could collide. Before ADT 14, all fields were final, so as a result, all libraries had to have all their resources and associated Java code recompiled along with the main project whenever they were used. This was bad for performance, since it made builds very slow. It also prevented distributing library projects that didn't include the source code, limiting the usage scope of library projects.
The reason the fields are no longer final is that it means that the library jars can be compiled once and reused directly in other projects. As well as allowing distributing binary version of library projects (coming in r15), this makes for much faster builds.
Imagine If R.java
was still supposed to contain the final keyword, for every library module that you've included in your android project, recompilation needed to be done since then R.java
would be used by both the Android source code and libraries. Hence final keyword has been removed now. However, Butterknife still uses the final
as it doesn't care about the clashes but BindView
annotations internally use those type-annotations like @IdRes
, @StringRes
, @DrawableRes
, etc inside that ensures the type safety of variables declared to be consistent.
回答2:
I investigated further. In summary,
- Resource values in library projects are reassigned when main project is built
- "Final" needs to be removed to use reassigned values
- Values in R2 is not reassigned so it might conflict, but it is only marker for Annotation. The actual value used when finding views comes from R
Details are here: https://battleshippark.wordpress.com/2018/02/12/butterknife-library-project-r2-final/
来源:https://stackoverflow.com/questions/48577106/final-field-in-r2-java-in-butterknife