Skip to content

Most visited

Recently visited

navigation

Melhorar a inspeção de código com anotações

Usar ferramentas de inspeção de código como o Lint pode ajudar a encontrar problemas e aprimorá-lo, mas elas não passam disso. Os IDs de recurso do Android, por exemplo, usam um int para identificar strings, gráficos, cores e outros tipos de recurso, e, nesse caso, as ferramentas de inspeção não conseguem determinar quando você especificou um recurso de string onde deveria ter especificado uma cor. Essa situação significa que o seu aplicativo pode renderizar de forma incorreta ou apresentar falha geral na execução, mesmo se você usar a inspeção de código.

As anotações permitem que você disponibilize dicas para as ferramentas de inspeção de código, como o Lint, ajudando-as a detectar os problemas de código mais sutis. Elas são adicionadas na forma de tags de metadados anexadas a variáveis e parâmetros, e retornam valores para inspecionar os valores de retorno dos métodos, parâmetros passados, campos e variáveis locais. Quando usadas com ferramentas de inspeção de código, as anotações podem ajudar a detectar problemas, como exceções de ponteiro nulo e conflitos de tipo de recurso.

O Android oferece suporte a diversos tipos de anotação por meio da Biblioteca de suporte a anotações. Você pode acessar a biblioteca pelo pacote android.support.annotation.

Adicionar anotações ao projeto

Para permitir anotações no seu projeto, adicione a dependência support-annotations na biblioteca ou no aplicativo. Toda anotação adicionada é verificada quando se realiza uma inspeção no código ou a tarefa lint.

Adicionar dependência da biblioteca de anotações de apoio

A biblioteca de anotações de apoio é parte do Repositório de Suporte do Android Para adicionar anotações a um projeto, você deve baixar o repositório de suporte e adicionar a dependência support-annotations ao arquivo build.gradle.

  1. Abra o SDK Manager clicando em SDK Manager na barra de ferramentas ou selecionando Tools > Android > SDK Manager.
  2. Clique na guia SDK Tools.
  3. Amplie o Repositório de suporte e marque a caixa de seleção Android Support Repository.
  4. Clique em OK.
  5. Prossiga pelo assistente para instalar os pacotes.
  6. Adicione a dependência support-annotations ao projeto colocando a seguinte linha no bloco dependencies do arquivo build.gradle:
     dependencies { compile 'com.android.support:support-annotations:24.2.0' } 
    A versão da biblioteca que você baixou pode ser mais recente, por isso, confirme que o valor especificado aqui corresponde à versão da etapa 3.
  7. Na barra de tarefas ou na notificação de sincronização que aparece, clique em Sync Now.

Se você usa anotações no próprio módulo da biblioteca, as anotações são incluídas como parte do artefato Android Archive (AAR) em formato XML no arquivo annotations.zip. Adicionar a dependência support-annotations não introduz uma dependência para nenhum usuário abaixo no fluxo da biblioteca.

Se você quer usar anotações em um módulo do Gradle que não esteja usando o Android Plugin for Gradle (com.android.application ou com.android.library), mas sim o plug-in Java para Gradle, deve incluir o repositório do SDK explicitamente porque as bibliotecas de suporte do Android não são disponibilizadas pelo repositório Java JCenter.

repositories {
   jcenter()
   maven { url '<your-SDK-path>/extras/android/m2repository' }
}

Observação: Se estiver usando a biblioteca appcompat, não será preciso adicionar a dependência support-annotations. Como a biblioteca appcompat já depende da biblioteca de anotações, você tem acesso às anotações.

Para ver uma lista completa de anotações incluídas no repositório de suporte, leia o guia de referência da biblioteca de anotações de apoio ou use o recurso de preenchimento automático para exibir as opções disponíveis para a declaração import android.support.annotation..

Realizar inspeções no código

Para iniciar uma inspeção no código pelo Android Studio, que contém anotações de validação e verificação automática do Lint, selecione Analyze > Inspect Code na barra de menu. O Android Studio exibe mensagens de conflito para indicar eventuais problemas em que o código conflita com anotações e sugerir possíveis soluções.

Você também pode impor as anotações executando a tarefa lint pela linha de comando. Embora isso possa ser útil para identificar problemas junto a um servidor de integração contínua, observe que a tarefa lint não impõe anotações de nulidade (somente o Android Studio faz isso). Para saber mais sobre como ativar e executar inspeções do Lint, acesse Como melhorar o código com o Lint.

Observe que, embora os conflitos de anotação gerem advertências, elas não impedem a compilação do aplicativo.

Anotações de nulidade

Adicione as anotações @Nullable e @NonNull para verificar a nulidade de uma determinada variável, parâmetro ou valor de retorno. A anotação @Nullable indica uma variável, parâmetro ou valor de retorno que pode ser nulo, enquanto que @NonNull indica uma variável, parâmetro ou valor de retorno que não pode ser nulo.

Por exemplo, se uma variável local que contém um valor nulo é passada como um parâmetro a um método com a anotação @NonNull vinculada a esse parâmetro, compilar o código gera uma advertência que indica um conflito de não nulidade. Por outro lado, tentar referenciar o resultado de um método marcado com @Nullable sem antes verificar se o resultado é nulo gera uma advertência de nulidade. Você só deve usar @Nullable no valor de retorno de um método se todo uso do método for explicitamente verificado quanto à nulidade.

O exemplo a seguir vincula a anotação @NonNull aos parâmetros context e attrs para verificar se os valores do parâmetro passados não são nulos. Ele também verifica se o próprio método onCreateView() retorna nulo:

import android.support.annotation.NonNull;
...

    /** Add support for inflating the <fragment> tag. **/
    @NonNull
    @Override
    public View onCreateView(String name, @NonNull Context context,
      @NonNull AttributeSet attrs) {
      ...
      }
...

Análise de valores nulos

O Android Studio oferece suporte à execução de análise de valores nulos para determinar e inserir anotações de valores nulos automaticamente no código. Uma análise de valores nulos analisa os contratos em todas as hierarquias de método no código para detectar:

Em seguida, a análise insere automaticamente as anotações de nulo apropriadas nos locais detectados.

Para realizar uma análise de valores nulos no Android Studio, selecione Analyze > Infer Nullity. O Android Studio insere as anotações @Nullable e @NonNull do Android nos locais detectados no código. Depois de executar uma análise de valores nulos, é recomendado verificar as anotações inseridas.

Observação: Ao adicionar anotações de nulidade, o recurso de preenchimento automático pode sugerir as anotações @Nullable e @NotNull do IntelliJ em vez das anotações de nulidade do Android e podem importar automaticamente a biblioteca correspondente. No entanto, o verificador Lint do Android Studio só busca anotações de nulidade do Android. Quando verificar suas anotações, confirme se o projeto usa anotações de nulidade do Android para que o verificador do Lint possa notificar você corretamente durante a inspeção do código.

Anotações de recurso

Validar tipos de recurso pode ser útil porque as referências do Android a recursos, como drawables e strings, são passadas na forma de números inteiros. O código que espera que um parâmetro referencie um tipo específico de recurso, por exemplo, Drawables, pode ser passado no tipo de referência esperado de int, mas, na verdade, referenciar um tipo diferente de recurso, como um recurso R.string.

Por exemplo, adicione anotações @StringRes para verificar se um parâmetro de recurso contém uma referência a R.string, confirme mostrado abaixo:

public abstract void setTitle(@StringRes int resId) { … }

Durante a inspeção de código, a anotação gera uma advertência se uma referência a R.string não é passada no parâmetro.

As anotações de outros tipos de recurso, como @DrawableRes, @DimenRes, @ColorRes e @InterpolatorRes, podem ser adicionadas usando o mesmo formato de anotação e executadas durante a inspeção de código. Se os parâmetros aceitam diversos tipos de recurso, é possível colocar mais de uma dessas anotações neles. Use @AnyRes para indicar que o parâmetro com a anotação pode ser de qualquer tipo de recurso R.

Embora você possa usar @ColorRes para especificar que um parâmetro deve ser um recurso de cor, um número inteiro de cor (no formato RRGGBB ou AARRGGBB) não é reconhecido como um recurso de cor. Para evitar isso, use a anotação @ColorInt para indicar que um parâmetro deve ser um número inteiro de cor. As ferramentas de compilação sinalizarão código incorreto que passar um ID de recurso de cor como android.R.color.black, em vez de como um número inteiro de cor, aos métodos com anotações.

Anotações de encadeamento

As anotações de encadeamento verificam se um método é chamado em um tipo específico de encadeamento. As anotações de encadeamento a seguir são compatíveis:

Observação: As ferramentas de compilação tratam as anotações @MainThread e @UiThread como intercambiáveis, assim, você pode chamar métodos com @UiThread de métodos com @MainThread e vice-versa. No entanto, é possível que um encadeamento da IU seja diferente do encadeamento principal no caso de aplicativos do sistema terem diversas vistas em diferentes encadeamentos. Portanto, você deve inserir a anotação @UiThread em métodos associados à hierarquia de vistas de um aplicativo e a anotação @MainThread somente em métodos associados ao ciclo de vida de um aplicativo.

Se todos os métodos de uma classe compartilharem da mesma exigência de encadeamento, é possível adicionar uma única anotação de encadeamento à classe para verificar se todos os métodos da classe são chamados no mesmo tipo de encadeamento.

Um uso comum da anotação de encadeamento é para validar neutralizações de método na classe AsyncTask, pois essa classe realiza operações em segundo plano e publica os resultados somente no encadeamento da IU.

Anotações de limitação de valor

Use as anotações @IntRange, @FloatRange e @Size para validar os valores dos parâmetros passados. Tanto @IntRange quanto @FloatRange funcionam melhor se aplicadas a parâmetros para os quais os usuários têm mais chance de não entender o intervalo corretamente.

A anotação @IntRange confirma que um valor de número inteiro ou longo de parâmetro está dentro de um intervalo especificado. O exemplo a seguir garante que o parâmetro alpha contenha um valor de número inteiro de 0 a 255:

public void setAlpha(@IntRange(from=0,to=255) int alpha) { … }

A anotação @FloatRange verifica se um valor de parâmetro flutuante ou duplo está dentro de um intervalo específico de valores de ponto flutuante. O exemplo a seguir garante que o parâmetro alpha contenha um valor flutuante de 0.0 a 1.0:

public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {...}

A anotação @Size verifica o tamanho de um conjunto ou de uma matriz, além do tamanho de uma string. A anotação @Size pode ser usada para verificar as seguintes qualidades:

Por exemplo, @Size(min=1) verifica se um conjunto está vazio e @Size(3) confirma que uma matriz contém exatamente três valores. O exemplo a seguir garante que a matriz location contenha pelo menos um elemento:

int[] location = new int[3];
button.getLocationOnScreen(@Size(min=1) location);

Anotações de permissão

Use a anotação @RequiresPermission para validar as permissões do autor da chamada de um método. Para verificar a presença de uma única permissão e uma lista de permissões válidas, use o atributo anyOf. Para verificar a presença de um conjunto de permissões, use o atributo allOf. O exemplo a seguir insere anotação no método setWallpaper() para garantir que o autor da chamada do método tenha a permissão permission.SET_WALLPAPERS:

@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;

Nesse exemplo, o autor da chamada do método copyFile() é obrigado a ter permissões de leitura e gravação no armazenamento externo:

@RequiresPermission(allOf = {
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.WRITE_EXTERNAL_STORAGE})
public static final void copyFile(String dest, String source) {
    ...
}

Para permissões de intents, coloque o requisito de permissão no campo “string” que define o nome da ação da intent:

@RequiresPermission(android.Manifest.permission.BLUETOOTH)
public static final String ACTION_REQUEST_DISCOVERABLE =
            "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";

Para permissões de provedores de conteúdo para os quais é preciso separar permissões de acesso de leitura das de gravação, encapsule cada requisito de permissão em uma anotação @RequiresPermission.Read ou @RequiresPermission.Write :

@RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");

Permissões indiretas

Quando uma permissão depende do valor específico fornecido a um parâmetro do método, use @RequiresPermission no próprio parâmetro, sem listar as permissões específicas. Por exemplo, o método startActivity(Intent) usa uma permissão indireta na intent passada ao método:

public abstract void startActivity(@RequiresPermission Intent intent, @Nullable Bundle) {...}

Quando se usa permissões indiretas, as ferramentas de compilação realizam uma análise do fluxo de dados para verificar se o argumento passado no método tem alguma anotação @RequiresPermission. Em seguida, elas impõem todas as anotações existentes do parâmetro no próprio método. No exemplo do startActivity(Intent), as anotações da classe Intent geram as advertências resultantes em usos inválidos do startActivity(Intent) quando uma intent sem as permissões necessárias é passada ao método, como exibido na figura 1.

Figura 1. A advertência gerada por uma anotação de permissões indiretas no método startActivity(Intent).

As ferramentas de compilação geram a advertência em startActivity(Intent) da anotação no nome da ação da intent correspondente da classe Intent:

@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@RequiresPermission(Manifest.permission.CALL_PHONE)
public static final String ACTION_CALL = "android.intent.action.CALL";

Se necessário, é possível trocar @RequiresPermission por @RequiresPermission.Read e/ou @RequiresPermission.Write ao inserir anotação em um parâmetro do método. No entanto, para permissões indiretas, não se deve usar @RequiresPermission com nenhuma anotação de permissão de leitura ou gravação.

Anotações de valor de retorno

Use a anotação @CheckResult para confirmar que o resultado ou valor de retorno de um método seja efetivamente usado. Em vez de inserir a anotação @CheckResult em todo método não nulo, adicione a anotação para esclarecer os resultados de métodos possivelmente confusos. Por exemplo, novos desenvolvedores Java muitas vezes, por engano, acham que <String>.trim() remove espaços em branco da string original. Inserir a anotação @CheckResult no método sinaliza usos de <String>.trim() em que o autor da chamada não faz nada com o valor de retorno do método.

O exemplo a seguir insere uma anotação no método checkPermissions() para garantir que o valor de retorno do método seja efetivamente referenciado. Ele também nomeia o método enforcePermission() como um método a ser sugerido ao desenvolvedor como substituto:

@CheckResult(suggest="#enforcePermission(String,int,int,String)")
public abstract int checkPermission(@NonNull String permission, int pid, int uid);

Anotações CallSuper

Use a anotação @CallSuper para confirmar que um método substituto chama a superimplementação do método. O exemplo a seguir insere uma anotação no método onCreate() para garantir que todas as implementações de método substituto chamem super.onCreate():

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

Anotações Typedef

Use as anotações @IntDef e @StringDef para poder criar anotações enumeradas de conjuntos de números inteiros e strings para validar outros tipos de referência de código. As anotações Typedef garantem que determinado parâmetro, valor de retorno ou campo referencie um conjunto específico de constantes. Elas também permitem que o preenchimento de código ofereça automaticamente as constantes permitidas.

As anotações Typedef usam @interface para declarar o novo tipo de anotação enumerada. As anotações @IntDef e @StringDef, junto com a @Retention, inserem a nova anotação e são necessárias para definir o tipo enumerado. A anotação @Retention(RetentionPolicy.SOURCE) instrui o compilador a não armazenar os dados da anotação enumerada no arquivo .class.

O exemplo a seguir ilustra as etapas para criar uma anotação que garanta que um valor passado como um parâmetro do método referencie uma das constantes definidas:

import android.support.annotation.IntDef;
...
public abstract class ActionBar {
    ...
    // Define the list of accepted constants and declare the NavigationMode annotation
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
    public @interface NavigationMode {}

    // Declare the constants
    public static final int NAVIGATION_MODE_STANDARD = 0;
    public static final int NAVIGATION_MODE_LIST = 1;
    public static final int NAVIGATION_MODE_TABS = 2;

    // Decorate the target methods with the annotation
    @NavigationMode
    public abstract int getNavigationMode();

    // Attach the annotation
    public abstract void setNavigationMode(@NavigationMode int mode);

Se o parâmetro mode não referenciar uma das constantes definidas (NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST ou NAVIGATION_MODE_TABS) na compilação desse código, uma advertência será gerada.

Você também pode combinar @IntDef e @IntRange para indicar que um número inteiro pode receber um conjunto de constantes ou um valor dentro de um intervalo.

Ativar combinação de constantes com sinalizadores

Se os usuários puderem combinar as constantes permitidas com um sinalizador (como |, &, ^ e outros), você poderá definir uma anotação com o atributo flag para verificar se um parâmetro ou valor de retorno referencia um padrão válido. O exemplo a seguir cria a anotação DisplayOptions com uma lista de constantes DISPLAY_ válidas:

import android.support.annotation.IntDef;
...

@IntDef(flag=true, value={
        DISPLAY_USE_LOGO,
        DISPLAY_SHOW_HOME,
        DISPLAY_HOME_AS_UP,
        DISPLAY_SHOW_TITLE,
        DISPLAY_SHOW_CUSTOM
})
@Retention(RetentionPolicy.SOURCE)
public @interface DisplayOptions {}

...

Se o parâmetro ou o valor de retorno decorado não referenciar um padrão válido durante a compilação do código com um sinalizador de anotação, uma advertência será gerada.

Anotações de acessibilidade do código

Use as anotações @VisibleForTesting e @Keep para indicar a acessibilidade de um método, classe ou campo.

A anotação @VisibleForTesting indica que um bloco de código está mais visível do que o necessário para tornar o código testável.

A anotação @Keep garante que um elemento com anotação não seja removido quando o código for minificado em tempo de compilação. Ela normalmente é adicionada a métodos e classes acessados por reflexão para impedir que o compilador acredite que o código não está sendo usado.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Follow Google Developers on WeChat

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience. (Dec 2017 Android Platform & Tools Survey)