При работе с правилами сохранения важно достичь необходимой степени детализации, чтобы получить преимущества, сохраняя при этом поведение вашего приложения. В следующих разделах вы узнаете о хороших шаблонах, а также о том, чего следует избегать в правилах сохранения.
Хорошие закономерности в правилах сохранения
Четко определенные правила сохранения данных максимально конкретны и соответствуют следующим закономерностям:
При указании класса всегда, по возможности, указывайте конкретный класс, базовый класс или аннотированный класс, как показано в следующих примерах:
-keepclassmembers class com.example.MyClass { void someSpecificMethod(); }-keepclassmembers ** extends com.example.MyBaseClass { void someSpecificMethod(); }-keepclassmembers @com.example.MyAnnotation class ** { void someSpecificMethod(); }По возможности используйте аннотации в исходном коде, а затем напрямую указывайте эти аннотации в правилах сохранения. Это создаст четкую и явную связь между вашим кодом и правилами, которые его сохраняют, что сделает вашу конфигурацию более надежной, понятной и менее подверженной сбоям при изменении кода.
Например, следующий фрагмент кода демонстрирует, как можно сохранить класс MyClass, а также другие классы, аннотированные
@com.example.DisplayComponent:// In the source code @com.example.DisplayComponent class MyClass { /* ... */ } // In the keep rules -keep @com.example.DisplayComponent class * {*;}Мы рекомендуем называть аннотации таким образом, чтобы они предоставляли осмысленный контекст, объясняющий, почему сохраняются определенные части кода. Например, используйте
@DisplayComponentдля приложения, где для компонентов отображения необходимо сохранять некоторые части кода.По возможности, спецификацию членов класса следует объявлять и ссылаться только на те части класса, которые необходимы для функционирования приложения. Рекомендуется не применять правило ко всему классу, определяя необязательную область видимости членов как
{ *; }если это строго не требуется.-keepclassmembers com.example.MyClass { void someSpecificMethod(); void @com.example.MyAnnotation *; }Если вы используете глобальную опцию
repackageclasses, избегайте указания необязательного имени пакета. Это приводит к уменьшению размера DEX-файлов, поскольку префикс пакета опускается в именах переупакованных классов.Необходимо поддерживать правила сохранения для всех элементов, к которым осуществляется доступ с помощью рефлексии. Даже если R8 сохраняет такие элементы без явных правил сохранения, поддержание фактических правил имеет решающее значение, поскольку будущие изменения кода могут привести к тому, что R8 перестанет сохранять эти элементы.
По возможности используйте
-assumenosideeffectsили-convertchecknotnullдля оптимизации проверок на null, поскольку это может значительно уменьшить размер DEX-файла вашего приложения. Для получения дополнительной информации см. раздел «Дополнительные типы правил» .
Если вы не можете придерживаться этих рекомендаций, вы можете временно изолировать код, который необходимо сохранить, в отдельном пакете и применить к нему правило сохранения. Однако это не является долгосрочным решением. Для получения дополнительной информации см. раздел «Постепенное внедрение оптимизаций» . Чтобы использовать правило сохранения для пакета, определите его, как показано в следующем примере:
-keepclassmembers class com.example.pkg.** { *; }
Чего следует избегать
В синтаксисе правила сохранения есть множество опций, но для достижения измеримых и устойчивых преимуществ в производительности мы рекомендуем не использовать следующие:
- Не используйте правила сохранения кода, действующие для всего пакета, такие как
-keep class com.example.pkg.** { *; }в долгосрочной перспективе. Их можно использовать временно для обхода проблем при настройке R8. Дополнительную информацию см. в разделе «Ограничение области оптимизации» . В целом, будьте осторожны с подстановочными знаками — убедитесь, что вы сохраняете только необходимый код. - По возможности избегайте библиотек, которые предлагают копировать и вставлять правила сохранения данных при их использовании, особенно правила сохранения данных, действующие на уровне всего пакета. Библиотеки, разработанные для эффективной работы на Android, должны по возможности избегать использования рефлексии и внедрять правила сохранения данных, зависящие от конкретного пользователя, только при необходимости .
- Избегайте использования оператора инверсии
!в правилах сохранения, поскольку вы можете непреднамеренно применить правило почти ко всем классам в вашем приложении.
Если вы не можете следовать этим правилам, возможно, вы слишком часто используете рефлексию в свободном режиме, и вам следует либо избегать рефлексии, либо избегать использования рефлексии в библиотеке (см. пример использования Gson ).