Следуйте лучшим практикам

При работе с правилами сохранения важно достичь необходимой степени детализации, чтобы получить преимущества, сохраняя при этом поведение вашего приложения. В следующих разделах вы узнаете о хороших шаблонах, а также о том, чего следует избегать в правилах сохранения.

Хорошие закономерности в правилах сохранения

Четко определенные правила сохранения данных максимально конкретны и соответствуют следующим закономерностям:

  • При указании класса всегда, по возможности, указывайте конкретный класс, базовый класс или аннотированный класс, как показано в следующих примерах:

    -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 ).