Améliorer l'inspection de code avec des annotations

Les outils d'inspection du code tels que lint peuvent vous aider à détecter des problèmes et à améliorer votre code, mais ils ne peuvent pas tout déduire. Les ID des ressources Android, par exemple, utilisent un int pour identifier les chaînes, les images, les couleurs et autres types de ressources. Les outils d'inspection ne peuvent donc pas savoir si vous avez spécifié une ressource de chaîne alors que vous auriez dû spécifier une couleur. Dès lors, il se peut que votre application ne s'affiche pas correctement, voire qu'elle ne s'exécute pas du tout, même si vous utilisez l'inspection du code.

Les annotations vous permettent de fournir des indications à des outils d'inspection de code tels que lint pour vous aider à détecter ces problèmes de code plus subtils. Elles sont ajoutées en tant que balises de métadonnées que vous joignez aux variables, aux paramètres et aux valeurs de retour afin d'inspecter les valeurs de retour, les paramètres transmis, les variables locales et les champs de la méthode. Lorsqu'elles sont utilisées avec des outils d'inspection de code, les annotations peuvent vous aider à détecter des problèmes, tels que des exceptions de pointeurs nuls et des conflits de types de ressources.

Android accepte diverses annotations via la bibliothèque Jetpack Annotations. Vous pouvez accéder à cette bibliothèque via le package androidx.annotation.

Remarque : Si un module a une dépendance sur un processeur d'annotations, vous devez utiliser la configuration de dépendance kapt ou ksp pour Kotlin, ou annotationProcessor pour Java afin d'ajouter cette dépendance.

Ajouter des annotations à votre projet

Pour activer les annotations dans votre projet, ajoutez la dépendance androidx.annotation:annotation à votre bibliothèque ou application. Toutes les annotations que vous ajoutez sont vérifiées lorsque vous exécutez une inspection de code ou une tâche lint.

Ajouter la dépendance de la bibliothèque Jetpack Annotations

La bibliothèque Jetpack Annotations est publiée dans le dépôt Maven de Google. Pour ajouter la bibliothèque Jetpack Annotations à votre projet, incluez la ligne suivante dans le bloc dependencies de votre fichier build.gradle ou build.gradle.kts :

Kotlin

dependencies {
    implementation("androidx.annotation:annotation:1.9.1")
}

Groovy

dependencies {
    implementation 'androidx.annotation:annotation:1.9.1'
}
Ensuite, dans la barre d'outils ou dans la notification de synchronisation qui s'affiche, cliquez sur Synchroniser.

Si vous utilisez des annotations dans votre module de bibliothèque, elles sont incluses dans l'artefact d'archive Android (AAR) au format XML dans le fichier annotations.zip. L'ajout de la dépendance androidx.annotation n'entraîne aucune dépendance pour les utilisateurs en aval de votre bibliothèque.

Remarque : Si vous utilisez d'autres bibliothèques Jetpack, vous n'aurez peut-être pas besoin d'ajouter la dépendance androidx.annotation. Comme de nombreuses autres bibliothèques Jetpack dépendent de la bibliothèque Annotations, il se peut que vous ayez déjà accès aux annotations.

Pour obtenir la liste complète des annotations incluses dans le dépôt Jetpack, consultez la documentation de référence sur la bibliothèque Jetpack Annotations ou utilisez la fonctionnalité de saisie semi-automatique pour afficher les options disponibles pour l'instruction import androidx.annotation..

Exécuter des inspections de code

Pour lancer une inspection de code depuis Android Studio, ce qui inclut la validation des annotations et la vérification automatique du code par lint, sélectionnez Analyze > Inspect Code (Analyser > Inspecter le code) dans le menu. Android Studio affiche des messages pour signaler des problèmes potentiels lorsque votre code est en conflit avec des annotations et pour suggérer des solutions possibles.

Vous pouvez également appliquer des annotations en exécutant la tâche lint à l'aide de la ligne de commande. Bien qu'il puisse être utile de signaler les problèmes liés à un serveur d'intégration continue, la tâche lint n'applique pas les annotations de nullité (décrites dans la section suivante). Seul Android Studio le permet. Pour en savoir plus sur l'activation et l'exécution des inspections lint, consultez Améliorer votre code avec des vérifications lint.

Même si les conflits d'annotations génèrent des avertissements, ceux-ci n'empêchent pas la compilation de votre application.

Annotations de nullité

Les annotations de nullité peuvent être utiles dans le code Java pour indiquer si les valeurs peuvent être nulles. Elles sont moins utiles dans le code Kotlin, car Kotlin dispose de règles intégrées concernant les valeurs nulles qui s'appliquent au moment de la compilation.

Ajoutez les annotations @Nullable et @NonNull pour vérifier la nullité d'une variable, d'un paramètre ou d'une valeur de retour spécifique. L'annotation @Nullable indique une variable, un paramètre ou une valeur de retour qui peuvent être nuls. @NonNull indique une variable, un paramètre ou une valeur de retour qui ne peuvent pas être nuls.

Par exemple, si une variable locale contenant une valeur nulle est transmise en tant que paramètre à une méthode avec l'annotation @NonNull jointe à ce paramètre, la compilation du code génère un avertissement indiquant un conflit non nul. En outre, le fait d'essayer de référencer le résultat d'une méthode marquée par @Nullable sans vérifier au préalable si le résultat est nul génère un avertissement de nullité. N'utilisez @Nullable sur la valeur de retour d'une méthode que si la nullité doit être explicitement vérifiée à chaque utilisation de la méthode.

L'exemple suivant illustre la possibilité de valeur nulle en action. L'exemple de code Kotlin n'exploite pas l'annotation @NonNull, car elle est automatiquement ajoutée au bytecode généré lorsqu'un type ne pouvant être nul est spécifié. L'exemple Java exploite l'annotation @NonNull sur les paramètres context et attrs pour vérifier que les valeurs des paramètres transmis ne sont pas nulles. Il vérifie également que la méthode onCreateView() ne renvoie pas de valeur nulle :

Kotlin

...
    /** Annotation not used because of the safe-call operator(?)**/
    override fun onCreateView(
            name: String?,
            context: Context,
            attrs: AttributeSet
    ): View? {
        ...
    }
...

Java

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

Analyse de la possibilité de valeur nulle

Android Studio permet d'exécuter une analyse de la possibilité de valeur nulle pour déduire automatiquement des annotations de nullité et les insérer dans votre code. Une analyse de la possibilité de valeur nulle passe en revue les contrats dans les hiérarchies de méthodes de votre code afin de détecter ce qui suit :

  • Méthodes d'appel pouvant renvoyer une valeur nulle
  • Méthodes qui ne doivent pas renvoyer une valeur nulle
  • Variables (telles que des champs, des variables locales et des paramètres) pouvant être nulles
  • Variables (telles que des champs, des variables locales et des paramètres) ne pouvant pas contenir de valeur nulle

L'analyse insère alors automatiquement les annotations de nullité appropriées aux emplacements détectés.

Pour exécuter une analyse de la possibilité de valeur nulle dans Android Studio, sélectionnez Analyze > Infer Nullity (Analyser > Déduire la possibilité de valeur nulle). Android Studio insère les annotations Android @Nullable et @NonNull aux emplacements détectés dans votre code. Après avoir exécuté une analyse de la possibilité de valeur nulle, nous vous recommandons de vérifier les annotations injectées.

Remarque : Lors de l'ajout d'annotations de nullité, la saisie semi-automatique peut suggérer des annotations IntelliJ @Nullable et @NotNull plutôt que des annotations de nullité Android et importer automatiquement la bibliothèque correspondante. Toutefois, l'outil de vérification lint d'Android Studio ne recherche que les annotations de nullité Android. Lorsque vous vérifiez vos annotations, assurez-vous que votre projet utilise des annotations de nullité Android pour permettre à l'outil lint de vous avertir correctement au cours de l'inspection du code.

Annotations de ressources

La validation des types de ressources peut être utile, car les références Android aux ressources, telles que les ressources de type drawable et string, sont transmises sous forme d'entiers.

Le code qui attend un paramètre pour référencer un type spécifique de ressource, comme une String, peut être transmis au type de référence attendu int, mais il fait en réalité référence à un autre type de ressource (comme R.string).

Par exemple, ajoutez des annotations @StringRes pour vérifier si un paramètre de ressource contient une référence R.string, comme indiqué ci-dessous :

Kotlin

abstract fun setTitle(@StringRes resId: Int)

Java

public abstract void setTitle(@StringRes int resId)

Lors de l'inspection du code, l'annotation génère un avertissement si aucune référence R.string n'est transmise dans le paramètre.

Les annotations pour les autres types de ressources, tels que @DrawableRes, @DimenRes, @ColorRes et @InterpolatorRes, peuvent être ajoutées en utilisant le même format d'annotation et s'exécuter lors de l'inspection du code.

Si votre paramètre prend en charge différents types de ressources, vous pouvez placer plusieurs annotations de ces types de ressources sur un paramètre donné. Utilisez @AnyRes pour indiquer que le paramètre annoté peut correspondre à n'importe quel type de ressource R.

Vous pouvez utiliser @ColorRes pour spécifier qu'un paramètre doit correspondre à une ressource de couleur. Cependant, un entier de couleur (au format RRGGBB ou AARRGGBB) n'est pas reconnu en tant que ressource de couleur. Utilisez plutôt l'annotation @ColorInt pour indiquer qu'un paramètre doit correspondre à un entier de couleur. Les outils de compilation signalent un code incorrect qui transmet un ID de ressource de couleur, tel que android.R.color.black, plutôt qu'un entier de couleur, aux méthodes annotées.

Annotations de thread

Les annotations de thread permettent de vérifier si une méthode est appelée à partir d'un type de thread spécifique. Les annotations de thread suivantes sont prises en charge :

Les outils de compilation considèrent les annotations @MainThread et @UiThread comme interchangeables. Vous pouvez donc appeler des méthodes @UiThread à partir des méthodes @MainThread et inversement. Toutefois, il est possible qu'un thread UI soit différent du thread principal dans le cas d'applications système dotées de plusieurs vues sur différents threads. Par conséquent, vous devez annoter les méthodes associées à la hiérarchie des vues d'une application avec @UiThread et n'annoter que les méthodes associées au cycle de vie d'une application avec @MainThread.

Si toutes les méthodes d'une classe présentent les mêmes exigences de thread, vous pouvez ajouter une seule annotation de thread à la classe afin de vérifier que toutes les méthodes correspondantes sont appelées à partir du même type de thread.

Les annotations de thread sont couramment utilisées pour vérifier que les méthodes ou les classes annotées avec @WorkerThread ne sont appelées qu'à partir d'un thread d'arrière-plan approprié.

Annotations de contrainte de valeur

Utilisez les annotations @IntRange, @FloatRange et @Size pour valider les valeurs des paramètres transmis. @IntRange et @FloatRange sont particulièrement utiles lorsqu'elles sont appliquées à des paramètres pouvant être sources d'erreurs pour les utilisateurs.

L'annotation @IntRange vérifie qu'un entier ou un paramètre long se situe dans une plage spécifiée. L'exemple suivant indique que le paramètre alpha doit contenir une valeur entière comprise entre 0 et 255 :

Kotlin

fun setAlpha(@IntRange(from = 0, to = 255) alpha: Int) { ... }

Java

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

L'annotation @FloatRange vérifie si une valeur de paramètre flottant ou double se situe dans une plage spécifiée de valeurs à virgule flottante. L'exemple suivant indique que le paramètre alpha doit contenir une valeur flottante comprise entre 0.0 et 1.0 :

Kotlin

fun setAlpha(@FloatRange(from = 0.0, to = 1.0) alpha: Float) {...}

Java

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

L'annotation @Size vérifie la taille d'une collection ou d'un tableau, ou la longueur d'une chaîne. L'annotation @Size permet de vérifier les qualités suivantes :

  • Taille minimale (@Size(min=2), par exemple)
  • Taille maximale (@Size(max=2), par exemple)
  • Taille exacte (@Size(2), par exemple)
  • Nombre dont la taille doit être un multiple (@Size(multiple=2), par exemple)

Par exemple, @Size(min=1) vérifie si une collection n'est pas vide, et @Size(3) vérifie qu'un tableau contient exactement trois valeurs.

L'exemple suivant indique que le tableau location doit contenir au moins un élément :

Kotlin

fun getLocation(button: View, @Size(min=1) location: IntArray) {
    button.getLocationOnScreen(location)
}

Java

void getLocation(View button, @Size(min=1) int[] location) {
    button.getLocationOnScreen(location);
}

Annotations d'autorisation

Utilisez l'annotation @RequiresPermission pour valider les autorisations de l'appelant d'une méthode. Pour rechercher une seule autorisation dans une liste d'autorisations valides, utilisez l'attribut anyOf. Pour vérifier un ensemble d'autorisations, utilisez l'attribut allOf. L'exemple suivant annote la méthode setWallpaper() pour indiquer que l'appelant de la méthode doit disposer de l'autorisation permission.SET_WALLPAPERS :

Kotlin

@RequiresPermission(Manifest.permission.SET_WALLPAPER)
@Throws(IOException::class)
abstract fun setWallpaper(bitmap: Bitmap)

Java

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

L'exemple suivant implique que l'appelant de la méthode copyImageFile() dispose d'un accès en lecture à l'espace de stockage externe ainsi qu'aux métadonnées de lieu dans l'image copiée :

Kotlin

@RequiresPermission(allOf = [
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.ACCESS_MEDIA_LOCATION
])
fun copyImageFile(dest: String, source: String) {
    ...
}

Java

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

Pour les autorisations relatives aux intents, placez l'exigence d'autorisation dans le champ de chaîne définissant le nom de l'action d'intent :

Kotlin

@RequiresPermission(android.Manifest.permission.BLUETOOTH)
const val ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"

Java

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

Pour les autorisations liées aux fournisseurs de contenu impliquant des autorisations distinctes pour l'accès en lecture et en écriture, encapsulez chaque exigence d'autorisation dans une annotation @RequiresPermission.Read ou @RequiresPermission.Write :

Kotlin

@RequiresPermission.Read(RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(RequiresPermission(WRITE_HISTORY_BOOKMARKS))
val BOOKMARKS_URI = Uri.parse("content://browser/bookmarks")

Java

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

Autorisations indirectes

Lorsqu'une autorisation dépend de la valeur spécifique fournie pour le paramètre d'une méthode, utilisez @RequiresPermission sur le paramètre lui-même, sans lister les autorisations spécifiques. Par exemple, la méthode startActivity(Intent) utilise une autorisation indirecte sur l'intent transmis à la méthode :

Kotlin

abstract fun startActivity(@RequiresPermission intent: Intent, bundle: Bundle?)

Java

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

Lorsque vous utilisez des autorisations indirectes, les outils de compilation effectuent une analyse de flux de données pour vérifier si l'argument transmis dans la méthode comporte des annotations @RequiresPermission. Ils appliquent ensuite toutes les annotations existantes du paramètre à la méthode. Dans l'exemple startActivity(Intent), les annotations de la classe Intent se traduisent par des avertissements d'utilisation incorrecte de startActivity(Intent) lorsqu'un intent sans autorisations appropriées est transmis à la méthode, comme illustré dans la figure 1.

Figure 1. Avertissement généré à partir d'une annotation d'autorisation indirecte sur la méthode startActivity(Intent).

Les outils de compilation génèrent l'avertissement sur startActivity(Intent) à partir de l'annotation sur le nom de l'action d'intent correspondant dans la classe Intent :

Kotlin

@RequiresPermission(Manifest.permission.CALL_PHONE)
const val ACTION_CALL = "android.intent.action.CALL"

Java

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

Si nécessaire, vous pouvez remplacer @RequiresPermission par @RequiresPermission.Read ou @RequiresPermission.Write lorsque vous annotez un paramètre de méthode. Toutefois, pour les autorisations indirectes, @RequiresPermission ne doit pas être utilisé avec les annotations des autorisations de lecture ou d'écriture.

Annotations de valeur de retour

Utilisez l'annotation @CheckResult pour vérifier que le résultat ou la valeur de retour d'une méthode sont effectivement utilisés. Plutôt que d'annoter toutes les méthodes non nulles avec @CheckResult, ajoutez l'annotation pour clarifier les résultats des méthodes qui peuvent prêter à confusion.

Par exemple, les nouveaux développeurs Java pensent souvent à tort que <String>.trim() supprime les espaces blancs de la chaîne d'origine. L'annotation de la méthode avec les indicateurs @CheckResult utilise <String>.trim(), où l'appelant n'effectue aucune action avec la valeur de retour de la méthode.

L'exemple suivant annote la méthode checkPermissions() pour vérifier si la valeur de retour de la méthode est effectivement référencée. Il nomme également la méthode enforcePermission() en tant que méthode de remplacement pour le développeur :

Kotlin

@CheckResult(suggest = "#enforcePermission(String,int,int,String)")
abstract fun checkPermission(permission: String, pid: Int, uid: Int): Int

Java

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

Annotations CallSuper

Utilisez l'annotation @CallSuper pour vérifier qu'une méthode de forçage appelle la super-implémentation de la méthode.

L'exemple suivant annote la méthode onCreate() pour faire en sorte que toutes les implémentations de la méthode de forçage appellent super.onCreate() :

Kotlin

@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
}

Java

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

Annotations typedef

Les annotations typedef permettent de vérifier si un paramètre, une valeur de retour ou un champ en particulier fait référence à un ensemble spécifique de constantes. Elles permettent également de compléter le code pour proposer automatiquement les constantes autorisées.

Utilisez les annotations @IntDef et @StringDef pour créer des annotations énumérées d'ensembles d'entiers et de chaînes, et valider d'autres types de références au code.

Les annotations typedef utilisent @interface pour déclarer le nouveau type d'annotation énuméré. Les annotations @IntDef et @StringDef, de même que @Retention, annotent la nouvelle annotation et sont nécessaires pour définir le type énuméré. L'annotation @Retention(RetentionPolicy.SOURCE) indique au compilateur de ne pas stocker les données d'annotation énumérées dans le fichier .class.

L'exemple suivant montre comment créer une annotation permettant de vérifier si une valeur transmise en tant que paramètre de méthode fait référence à l'une des constantes définies :

Kotlin

import androidx.annotation.IntDef
//...
// Define the list of accepted constants and declare the NavigationMode annotation.
@Retention(AnnotationRetention.SOURCE)
@IntDef(NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS)
annotation class NavigationMode

// Declare the constants.
const val NAVIGATION_MODE_STANDARD = 0
const val NAVIGATION_MODE_LIST = 1
const val NAVIGATION_MODE_TABS = 2

abstract class ActionBar {

    // Decorate the target methods with the annotation.
    // Attach the annotation.
    @get:NavigationMode
    @setparam:NavigationMode
    abstract var navigationMode: Int

}

Java

import androidx.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);
}

Lorsque vous créez ce code, un avertissement est généré si le paramètre mode ne fait pas référence à l'une des constantes définies (NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST ou NAVIGATION_MODE_TABS).

Combinez @IntDef et @IntRange pour indiquer qu'un entier peut être un ensemble donné de constantes ou une valeur dans une plage.

Activer la combinaison de constantes avec des indicateurs

Si les utilisateurs peuvent combiner les constantes autorisées avec un indicateur (tel que |, &, ^, etc.), vous pouvez définir une annotation avec un attribut flag pour vérifier si un paramètre ou une valeur de retour fait référence à un format valide.

L'exemple suivant crée l'annotation DisplayOptions avec une liste de constantes DISPLAY_ valides :

Kotlin

import androidx.annotation.IntDef
...

@IntDef(flag = true, value = [
    DISPLAY_USE_LOGO,
    DISPLAY_SHOW_HOME,
    DISPLAY_HOME_AS_UP,
    DISPLAY_SHOW_TITLE,
    DISPLAY_SHOW_CUSTOM
])
@Retention(AnnotationRetention.SOURCE)
annotation class DisplayOptions
...

Java

import androidx.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 {}

...

Lorsque vous créez du code avec un indicateur d'annotation, un avertissement est généré si le paramètre décoré ou la valeur de retour ne fait pas référence à un format valide.

Annotation de conservation

L'annotation @Keep permet de s'assurer qu'une classe ou méthode annotée n'est pas supprimée lorsque la taille du code est réduite au moment de la compilation. Cette annotation est généralement ajoutée aux méthodes et classes accessibles par réflexion afin d'empêcher le compilateur de traiter le code comme inutilisé.

Attention : Les classes et les méthodes que vous annotez à l'aide de @Keep apparaissent systématiquement dans l'APK de votre application, même si vous ne les référencez jamais dans la logique de votre application.

Pour réduire la taille de votre application, déterminez s'il est nécessaire de conserver chaque annotation @Keep dans votre application. Si vous utilisez la réflexion pour accéder à une classe ou à une méthode annotées, utilisez une condition -if dans vos règles ProGuard, en spécifiant la classe à l'origine des appels de réflexion.

Pour savoir comment minimiser la taille de votre code et spécifier le code à ne pas supprimer, consultez Réduire, obscurcir et optimiser votre application.

Annotations de visibilité du code

Utilisez les annotations suivantes pour indiquer la visibilité de parties de code spécifiques, telles que des méthodes, des classes, des champs ou des packages.

Rendre le code visible à des fins de test

L'annotation @VisibleForTesting indique qu'une méthode annotée est plus visible que d'ordinaire pour lui permettre d'être testée. Cette annotation contient un argument otherwise facultatif qui vous permet de désigner la visibilité de la méthode si vous n'avez pas besoin de la rendre visible pour les tests. Lint utilise l'argument otherwise pour appliquer la visibilité prévue.

Dans l'exemple suivant, myMethod() est normalement private, mais est package-private pour les tests. Avec la désignation VisibleForTesting.PRIVATE, lint affiche un message si cette méthode est appelée en dehors du contexte autorisé par l'accès à private, par exemple à partir d'une autre unité de compilation.

Kotlin

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun myMethod() {
    ...
}

Java

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
void myMethod() { ... }

Vous pouvez également spécifier @VisibleForTesting(otherwise = VisibleForTesting.NONE) pour indiquer qu'une méthode est réservée aux tests. Ce formulaire est identique à l'utilisation de @RestrictTo(TESTS). Tous deux effectuent le même contrôle d'analyse lint.

Restreindre une API

L'annotation @RestrictTo indique que l'accès à l'API annotée (package, classe ou méthode) est limité, comme suit :

Sous-classes

Utilisez le formulaire d'annotation @RestrictTo(RestrictTo.Scope.SUBCLASSES) pour limiter l'accès API aux sous-classes uniquement.

Seules les classes qui étendent la classe annotée peuvent accéder à cette API. Le modificateur Java protected n'est pas suffisamment restrictif, car il autorise l'accès à partir de classes non liées dans le même package. Par ailleurs, il peut arriver que vous souhaitiez quitter une méthode public pour plus de flexibilité, car vous ne pouvez pas créer de méthode protected précédemment remplacée par une méthode public, mais que vous souhaitez indiquer que la classe est destinée à être utilisée dans la classe ou depuis des sous-classes uniquement.

Bibliothèques

Utilisez le formulaire d'annotation @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) pour limiter l'accès API à vos bibliothèques uniquement.

Seul le code de votre bibliothèque peut accéder à l'API annotée. Cela vous permet non seulement d'organiser votre code dans la hiérarchie de packages de votre choix, mais aussi de le partager entre un groupe de bibliothèques liées. Cette option est déjà disponible pour les bibliothèques Jetpack dont une grande partie du code d'implémentation n'est pas destiné à un usage externe, mais devant correspondre à public pour le partager entre les différentes bibliothèques Jetpack supplémentaires.

Tests

Utilisez le formulaire d'annotation @RestrictTo(RestrictTo.Scope.TESTS) pour empêcher d'autres développeurs d'accéder à vos API de test.

Seul le code de test peut accéder à l'API annotée. Ainsi, les autres développeurs ne peuvent pas utiliser les API que vous destinez aux tests à des fins de développement.