Como Enums podem afetar o desempenho de aplicativos Android

Tempo de leitura: 4 minutes

De vez em quando, durante o desenvolvimento de aplicativos, você pode ter usado enums. Eles são úteis. Mas, quando você os usou, pode não ter conhecido o impacto total dos enums. Enums são muito convenientes, mas, infelizmente, podem ser dolorosos quando se trata de tamanho e velocidade da memória. Vamos explorar como enums afetam o desempenho e como paramos de usá-los.

 

 

O que é um Enum?

Um enum em Java é um tipo de dados que contém um conjunto fixo de constantes.

É um tipo de dados especial que permite que uma variável seja um conjunto cheio de constantes predefinidas. Sua variável deve ser igual a um dos valores predefinidos para ela.

 

Por que usamos Enums?

Usamos enums quando uma variável pode tirar apenas um valor de um conjunto de valores possíveis. Vejamos um exemplo:

public enum Fruits{ Apple, Bannana, Grape, Mango }

Agora, o enum denominado Frutas pode ter apenas um valor e não pode haver nenhum valor diferente de um desses que foram definidos.

Mas no caso de usarmos um inteiro ou constante de string, pode haver uma chance de passar constantes inválidas. Portanto, para evitar esses erros constantes inválidos e aumentar a verificação do tempo de compilação, geralmente usamos um enum.

 

O preço de Enums

Os valores de enum ocuparão mais memória em comparação com uma constante int. Adicionar um único enum aumentará o tamanho do arquivo DEX final em aproximadamente 13x quando para uma constante inteira.

Isso ocorre porque cada valor em uma classe enum é tratado como um objeto e cada valor vai usar um pouco de memória heap para fazer referência ao objeto. Isso corrói o espaço disponível em geap.

Quanto mais enums tivermos em nosso aplicativo, mais espaço será consumido.

Podemos nem saber que o enum está afetando o desempenho de nosso aplicativo. Talvez escrever uma ou duas classes enum não tenha um grande impacto em nosso aplicativo. Mas se você estiver usando algumas classes enum e as bibliotecas incluídas em seu aplicativo estão usando algumas outras classes enum, a combinação de todas essas enums pode ter um impacto considerável em seu aplicativo, o que pode aumentar o tamanho do arquivo – bem como afetar o desempenho.

Observação: os escritores da equipe da plataforma central recomendam enfaticamente não usar enums em nenhuma parte do código que escrevem.

 

Solução

O Android oferece suporte a uma variedade de anotações por meio da Biblioteca de Suporte de Anotações. Você pode acessar a biblioteca por meio do pacote android.support.annotation. Esta biblioteca possui anotações TypeDef. Essas anotações garantem que um determinado parâmetro, valor de retorno ou campo faça referência a um conjunto específico de constantes. Eles também permitem que o autocompletar de código ofereça automaticamente as constantes permitidas.

@IntDef e @StringDef são duas anotações constantes que podem ser usadas em vez de enums para constantes int e string que darão segurança no tempo de construção. Essas anotações nos ajudarão a verificar as atribuições de variáveis ​​- como um enum faria – em tempo de compilação.

 

Como usar anotações

Vamos entender isso usando um exemplo.

Temos uma classe Fruit com um conjunto de constantes int. Portanto, ao criar o objeto, precisamos passar o valor do tipo int do conjunto disponível. Mas no meu método principal, eu estava passando um valor que não estava no conjunto de constantes – o que pode levar a uma situação problemática. Não há segurança de tipo no snippet de código abaixo.

public class Fruit {  
     public static final int APPLE = 0;   
     public static final int BANNANA = 1;    
     public static final int GRAPE = 2;   
     public static final int MANGO = 3;

    public Fruit(int fruit) {   
       System.out.println("Fruit Selected:" + fruit);   
     }

     public static void main(String[] args) {     
       //Passing Invalid value       
       Fruit fruit = new Fruit(4);    
     }
}

Uma implementação de código semelhante usando enums é a seguinte:

public class EnumFruit {
 public EnumFruit(Fruit fruit) {             .                 
   System.out.println("Fruit selected is:" + fruit);
 }

 public enum Fruit {  
    APPLE, BANNANA, GRAPE, MANGO   
 }
 
 public static void main(String[] args) {        
   EnumFruit enumFruitInstance = new EnumFruit(Fruit.APPLE);  
 }
}

Adicione a dependência support-annotations no nível do aplicativo build.gradle:

dependencies {
    implementation 'com.android.support:support-annotations:28.0.0'
}

Declare as constantes e @IntDef para essas constantes:

public class AnnotationFruit {     
   public static final int APPLE = 0;    
   public static final int BANNANA = 1;  
   public static final int GRAPE = 2;    
   public static final int MANGO = 3;   
 
   public AnnotationFruit(@Fruit int fruit) {         
     System.out.println("Fruit Selected is :" + fruit);   
   }

   @IntDef({APPLE, BANNANA, GRAPE, MANGO})        
   @Retention(RetentionPolicy.SOURCE) 
   public @interface Fruit {}

   public static void main(String[] args) {       
     AnnotationFruit  annotationSeason = new AnnotationFruit(GRAPE);   
   }
}

No exemplo acima, as anotações Typedef usam:

  • @interface para declarar o novo tipo de anotação enumerada
  • As anotações @IntDef e @StringDef, junto com @Retention, são necessárias para definir o tipo enumerado

A anotação @Retention (RetentionPolicy.SOURCE) diz ao compilador para não armazenar os dados da anotação enumerados no arquivo .class.

Os setters e getters podem ser definidos da seguinte forma:

// Decore os métodos alvo com a anotação
@Fruit    
public abstract int getFruitName();
 
// Anexe a anotação
public abstract void setFruitName(@Fruit int fuitValue);

Se o Proguard estiver configurado corretamente, ele pode otimizar enums para valores int em nosso nome em algumas ou muitas situações. Portanto, não precisamos nos preocupar.

Conclusão

Enums adicionam pelo menos 2x mais bytes ao tamanho total do APK do que constantes simples e podem usar aproximadamente 5 a 10x mais RAM do que constantes equivalentes.

Portanto, se você deseja que seu aplicativo seja eficiente em termos de memória e desempenho, tente evitar enums em seu código.

 

 

Obrigado por gastar seu tempo lendo este artigo. Compartilhe se você gostou!