Последнее поле в R2.java в ButterKnife
Это расширение Android: почему нам нужно использовать R2 вместо R с ножом? и ссылка в R.java не окончательная
Я понимаю, что поля R.java в проекте библиотеки не имеют окончательного модификатора для защиты коллизий значений между проектами библиотеки. Однако ButterKnife восстанавливает окончательный модификатор в R2 и использует его.
Я думаю, что это идет к проблеме столкновения, и значения могут столкнуться, но нет проблемы. Как это работает?
===
Я добавляю примеры. Есть один основной проект и один библиотечный проект. Основной проект имеет com.main.R, а проект библиотеки имеет com.library.R.
- Когда происходит столкновение:
- com.main.R: public static final int = 0x1234
- com.library.R: public static int example = 0x1234
если инструменты сборки не перекомпилируют проект библиотеки, как мы можем избежать конфликта между этими значениями?
- Когда ButterKnife создает R2
- com.main.R: public static final int = 0x1234
- com.library.R: public static int example = 0x1234
- com.library.R2: public static final int example = 0x1234
У com.library.R2 есть коллизия, и даже у нее есть финальный модификатор. Разве это не создает проблемы? Зачем?
Спасибо
2 ответа
Хотя final
ключевое слово было удалено из R.java
сгенерированный класс, так как это отрицательно сказалось на производительности сборки, Butterknife использует только final
для себя, поэтому только код Butterknife необходимо перекомпилировать каждый раз, когда добавляется новый идентификатор. Хорошим моментом является то, что Butterknife использует аннотации, чтобы гарантировать, что тип, который мы возвращаем, всегда корректен.
Из документа:
Другими словами, константы не являются окончательными в проекте библиотеки. Причина этого проста: при объединении нескольких библиотечных проектов фактические значения полей (которые должны быть уникальными) могут конфликтовать. До ADT 14 все поля были окончательными, поэтому все библиотеки должны были перекомпилировать все свои ресурсы и связанный Java-код вместе с основным проектом, когда бы они ни использовались. Это плохо сказывалось на производительности, поскольку сборка выполнялась очень медленно. Это также предотвратило распространение библиотечных проектов, которые не включали исходный код, ограничивая область использования библиотечных проектов.
Причина, по которой поля больше не являются окончательными, заключается в том, что библиотечные файлы могут быть скомпилированы один раз и повторно использованы непосредственно в других проектах. Помимо возможности распространения двоичных версий библиотечных проектов (начиная с версии 15), это значительно ускоряет сборку.
Представь если R.java
предполагалось, что оно будет содержать последнее ключевое слово, для каждого библиотечного модуля, который вы включили в свой проект Android, с тех пор нужно было перекомпилировать R.java
будет использоваться как исходным кодом Android, так и библиотеками. Следовательно, последнее ключевое слово было удалено. Тем не менее, Butterknife по-прежнему использует final
как он не заботится о столкновениях, но BindView
аннотации внутри используют эти типовые аннотации, такие как @IdRes
, @StringRes
, @DrawableRes
и т. д. внутри, что обеспечивает безопасность типов переменных, объявленных как согласованные.
Я исследовал дальше. В итоге,
- Значения ресурсов в проектах библиотеки переназначаются при создании основного проекта
- "Final" необходимо удалить, чтобы использовать переназначенные значения
- Значения в R2 не переназначаются, поэтому могут конфликтовать, но это только маркер для аннотации. Фактическое значение, используемое при поиске представлений, исходит от R
Подробности здесь: https://battleshippark.wordpress.com/2018/02/12/butterknife-library-project-r2-final/