Migliora l'ispezione del codice con le annotazioni

L'utilizzo di strumenti di ispezione del codice come lint può aiutarti a individuare i problemi e a migliorare il codice, ma questi strumenti possono dedurre solo molto. Gli ID risorsa Android, ad esempio, utilizzano int per identificare stringhe, grafica, colori e altri tipi di risorse, in modo che gli strumenti di ispezione non siano in grado di stabilire quando hai specificato una risorsa stringa in cui avresti dovuto specificare un colore. Questa situazione indica che l'app potrebbe non essere visualizzata correttamente o non essere eseguita, anche se utilizzi l'ispezione del codice.

Le annotazioni ti consentono di fornire suggerimenti agli strumenti di ispezione del codice, come lint, per aiutarti a rilevare questi problemi più sottili con il codice. Le annotazioni vengono aggiunte come tag di metadati che associ a variabili, parametri e valori restituiti per esaminare i valori restituiti del metodo, i parametri passati, le variabili locali e i campi. Se utilizzate con gli strumenti di ispezione del codice, le annotazioni possono aiutare a rilevare problemi come eccezioni di puntatore nullo e conflitti tra tipi di risorse.

Android supporta una serie di annotazioni tramite la raccolta Annotazioni di Jetpack. Puoi accedere alla libreria tramite il pacchetto androidx.annotation.

Nota: se un modulo ha una dipendenza da un processore di annotazione, devi utilizzare la configurazione delle dipendenze kapt o ksp per Kotlin o la configurazione delle dipendenze annotationProcessor per Java per aggiungere questa dipendenza.

Aggiungi annotazioni al progetto

Per abilitare le annotazioni nel progetto, aggiungi la dipendenza androidx.annotation:annotation alla libreria o all'app. Tutte le annotazioni aggiunte vengono selezionate quando esegui un'ispezione del codice o un'attività lint.

Aggiungi la dipendenza dalla libreria di annotazioni Jetpack

La libreria delle annotazioni Jetpack è pubblicata nel repository Maven di Google. Per aggiungere la libreria Jetpack Anotations al tuo progetto, includi la seguente riga nel blocco dependencies del tuo file build.gradle o build.gradle.kts:

Kotlin

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

Alla moda

dependencies {
    implementation 'androidx.annotation:annotation:1.8.0'
}
Quindi, fai clic su Sincronizza ora nella barra degli strumenti o nella notifica di sincronizzazione visualizzata.

Se utilizzi le annotazioni nel tuo modulo della raccolta, queste vengono incluse nell'elemento dell'archivio Android (AAR) in formato XML nel file annotations.zip. L'aggiunta della dipendenza androidx.annotation non introduce una dipendenza per nessun utente downstream della libreria.

Nota: se utilizzi altre librerie Jetpack, potrebbe non essere necessario aggiungere la dipendenza androidx.annotation. Poiché molte altre librerie Jetpack dipendono dalla libreria delle annotazioni, potresti già avere accesso alle annotazioni.

Per un elenco completo delle annotazioni incluse nel repository Jetpack, consulta il riferimento della libreria di annotazioni Jetpack o utilizza la funzionalità di completamento automatico per visualizzare le opzioni disponibili per l'istruzione import androidx.annotation..

Esegui ispezioni del codice

Per avviare un'ispezione del codice da Android Studio, che include la convalida delle annotazioni e il controllo automatico del lint, seleziona Analizza > Ispeziona codice dal menu. Android Studio mostra messaggi di conflitto per segnalare potenziali problemi in cui il codice viene in conflitto con le annotazioni e per suggerire possibili soluzioni.

Puoi anche applicare le annotazioni eseguendo l'attività lint usando la riga di comando. Sebbene questo possa essere utile per segnalare problemi con un server di integrazione continua, l'attività lint non applica le annotazioni di nullità (descritte nella sezione seguente); questa operazione viene eseguita solo da Android Studio. Per ulteriori informazioni sull'abilitazione e l'esecuzione delle ispezioni dei lint, consulta Migliorare il codice con i controlli dei lint.

Sebbene i conflitti di annotazioni generino avvisi, questi avvisi non impediscono la compilazione della tua app.

Annotazioni nullità

Le annotazioni di nullità possono essere utili nel codice Java per stabilire se i valori possono essere nulli. Sono meno utili nel codice Kotlin, in quanto Kotlin ha regole basate su valori nulli integrate che vengono applicate in fase di compilazione.

Aggiungi le annotazioni @Nullable e @NonNull per verificare la nullità di una determinata variabile, parametro o valore restituito. L'annotazione @Nullable indica una variabile, un parametro o un valore restituito che può essere nullo. @NonNull indica una variabile, un parametro o un valore restituito che non può essere nullo.

Ad esempio, se una variabile locale contenente un valore nullo viene passata come parametro a un metodo con l'annotazione @NonNull associata a quel parametro, la creazione del codice genera un avviso che indica un conflitto diverso da null. Inoltre, il tentativo di fare riferimento al risultato di un metodo contrassegnato da @Nullable senza prima verificare se il risultato è nullo genera un avviso di nullità. Utilizza @Nullable sul valore restituito di un metodo solo se ogni utilizzo del metodo deve essere sottoposto esplicitamente a controllo null.

L'esempio seguente mostra l'uso di valori null in azione. Il codice di esempio Kotlin non utilizza l'annotazione @NonNull perché viene aggiunta automaticamente al bytecode generato quando viene specificato un tipo che non supporta null. L'esempio Java utilizza l'annotazione @NonNull sui parametri context e attrs per verificare che i valori dei parametri passati non siano nulli. Controlla inoltre che il metodo onCreateView() stesso non restituisca null:

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

Analisi di nullità

Android Studio supporta l'esecuzione di un'analisi dei valori nullità per dedurre e inserire automaticamente annotazioni di nullità nel codice. Un'analisi con supporto dei valori non validi scansiona i contratti attraverso le gerarchie di metodi nel codice per rilevare:

  • Metodi di chiamata che possono restituire un valore nullo.
  • Metodi che non devono restituire un valore nullo.
  • Variabili come campi, variabili locali e parametri, che possono essere nulle.
  • Variabili come campi, variabili locali e parametri, che non possono contenere un valore nullo.

L'analisi inserisce quindi automaticamente le annotazioni null appropriate nelle località rilevate.

Per eseguire un'analisi relativa ai valori NULL in Android Studio, seleziona Analyze > Infer nullity (Analizza nullità). Android Studio inserisce le annotazioni Android @Nullable e @NonNull nelle posizioni rilevate nel codice. Dopo aver eseguito un'analisi dei valori null, è buona norma verificare le annotazioni inserite.

Nota: quando aggiungi annotazioni nulle, il completamento automatico potrebbe suggerire le annotazioni IntelliJ @Nullable e @NotNull anziché le annotazioni null Android e potrebbe importare automaticamente la libreria corrispondente. Tuttavia, il controllo lint di Android Studio cerca solo le annotazioni null in Android. Quando verifichi le annotazioni, verifica che il progetto utilizzi le annotazioni null Android in modo che il controllo pelucchi possa inviarti notifiche adeguate durante l'ispezione del codice.

Annotazioni per le risorse

La convalida dei tipi di risorse può essere utile perché i riferimenti Android alle risorse, ad esempio le risorse drawable e string, vengono passati come numeri interi.

Il codice che prevede che un parametro faccia riferimento a un tipo specifico di risorsa, ad esempio String, può essere passato al tipo di riferimento previsto di int, ma in realtà fa riferimento a un tipo diverso di risorsa, ad esempio una risorsa R.string.

Ad esempio, aggiungi annotazioni @StringRes per verificare se un parametro risorsa contiene un riferimento R.string, come mostrato qui:

Kotlin

abstract fun setTitle(@StringRes resId: Int)

Java

public abstract void setTitle(@StringRes int resId)

Durante l'ispezione del codice, l'annotazione genera un avviso se nel parametro non viene passato un riferimento R.string.

Annotazioni per altri tipi di risorse, come @DrawableRes, @DimenRes, @ColorRes e @InterpolatorRes, possono essere aggiunte utilizzando lo stesso formato di annotazione ed eseguite durante l'ispezione del codice.

Se il parametro supporta più tipi di risorse, puoi inserire più di un'annotazione per il tipo di risorsa per un determinato parametro. Utilizza @AnyRes per indicare che il parametro annotato può essere qualsiasi tipo di risorsa R.

Sebbene sia possibile utilizzare @ColorRes per specificare che un parametro deve essere una risorsa colore, un numero intero colore (nel formato RRGGBB o AARRGGBB) non viene riconosciuto come risorsa colore. Utilizza invece l'annotazione @ColorInt per indicare che un parametro deve essere un numero intero di colore. Gli strumenti di build segnaleranno ai metodi annotati il codice errato che passa un ID risorsa colore come android.R.color.black, anziché un numero intero colore.

Annotazioni dei thread

Le annotazioni dei thread controllano se un metodo viene chiamato da un tipo specifico di thread. Sono supportate le seguenti annotazioni dei thread:

Gli strumenti di creazione trattano le annotazioni @MainThread e @UiThread come intercambiabili, quindi puoi chiamare i metodi @UiThread dai metodi @MainThread e viceversa. Tuttavia, è possibile che un thread della UI sia diverso dal thread principale nel caso di app di sistema con più visualizzazioni su thread diversi. Di conseguenza, devi annotare i metodi associati alla gerarchia delle visualizzazioni di un'app con @UiThread e annotare solo i metodi associati al ciclo di vita di un'app con @MainThread.

Se tutti i metodi in una classe condividono lo stesso requisito di organizzazione dei thread, puoi aggiungere una singola annotazione del thread alla classe per verificare che tutti i metodi della classe vengano richiamati dallo stesso tipo di thread.

Un uso comune delle annotazioni dei thread è per convalidare che i metodi o le classi annotati con @WorkerThread vengano richiamati solo da un thread in background appropriato.

Annotazioni dei vincoli di valore

Utilizza le annotazioni @IntRange, @FloatRange e @Size per convalidare i valori dei parametri trasmessi. Sia @IntRange sia @FloatRange sono più utili quando vengono applicati a parametri per cui è probabile che gli utenti visualizzino l'intervallo sbagliato.

L'annotazione @IntRange convalida che un valore parametro lungo o intero rientri in un intervallo specificato. L'esempio seguente indica che il parametro alpha deve contenere un valore intero compreso tra 0 e 255:

Kotlin

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

Java

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

L'annotazione @FloatRange verifica se il valore del parametro in virgola mobile o doppio è compreso in un intervallo specificato di valori in virgola mobile. L'esempio seguente indica che il parametro alpha deve contenere un valore in virgola mobile compreso tra 0,0 e 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'annotazione @Size controlla le dimensioni di una raccolta o un array o la lunghezza di una stringa. L'annotazione @Size può essere utilizzata per verificare le seguenti qualità:

  • Dimensioni minime, ad esempio @Size(min=2)
  • Dimensioni massime, ad esempio @Size(max=2)
  • Dimensioni esatte, ad esempio @Size(2)
  • Un numero di cui la dimensione deve essere un multiplo, ad esempio @Size(multiple=2)

Ad esempio, @Size(min=1) verifica se una raccolta non è vuota e @Size(3) convalida che un array contenga esattamente tre valori.

L'esempio seguente indica che l'array location deve contenere almeno un elemento:

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);
}

Annotazioni relative alle autorizzazioni

Utilizza l'annotazione @RequiresPermission per convalidare le autorizzazioni del chiamante per un metodo. Per verificare la presenza di una singola autorizzazione in un elenco di autorizzazioni valide, utilizza l'attributo anyOf. Per verificare la presenza di un insieme di autorizzazioni, utilizza l'attributo allOf. L'esempio seguente annota il metodo setWallpaper() per indicare che il chiamante del metodo deve avere l'autorizzazione 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'esempio seguente richiede che il chiamante del metodo copyImageFile() abbia sia l'accesso in lettura alla memoria esterna sia l'accesso in lettura ai metadati della posizione nell'immagine copiata:

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) {
    //...
}

Per le autorizzazioni per gli intent, inserisci il requisito di autorizzazione nel campo della stringa che definisce il nome dell'azione di 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";

Per le autorizzazioni per i fornitori di contenuti che richiedono autorizzazioni separate per l'accesso in lettura e scrittura, aggrega ogni requisito di autorizzazione in un'annotazione @RequiresPermission.Read o @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");

Autorizzazioni indirette

Quando un'autorizzazione dipende dal valore specifico fornito al parametro di un metodo, utilizza @RequiresPermission nel parametro stesso senza elencare le autorizzazioni specifiche. Ad esempio, il metodo startActivity(Intent) utilizza un'autorizzazione indiretta per l'intent passato al metodo:

Kotlin

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

Java

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

Quando utilizzi le autorizzazioni indirette, gli strumenti di creazione eseguono l'analisi del flusso di dati per verificare se l'argomento passato nel metodo ha annotazioni @RequiresPermission. Quindi, applicano in modo forzato tutte le annotazioni esistenti dal parametro sul metodo stesso. Nell'esempio startActivity(Intent), le annotazioni nella classe Intent causano gli avvisi risultanti in caso di utilizzi non validi di startActivity(Intent) quando al metodo viene passato un intent senza le autorizzazioni appropriate, come mostrato nella figura 1.

Figura 1. L'avviso generato da un'annotazione di autorizzazioni indirette sul metodo startActivity(Intent).

Gli strumenti di creazione generano l'avviso su startActivity(Intent) dall'annotazione sul nome dell'azione per intent corrispondente nella 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";

Se necessario, puoi sostituire @RequiresPermission con @RequiresPermission.Read o @RequiresPermission.Write quando aggiungi un'annotazione al parametro di un metodo. Tuttavia, per le autorizzazioni indirette @RequiresPermission non deve essere utilizzato insieme alle annotazioni delle autorizzazioni di lettura o di scrittura.

Annotazioni per i valori restituiti

Utilizza l'annotazione @CheckResult per convalidare l'effettivo utilizzo del risultato o del valore restituito di un metodo. Invece di annotare ogni metodo non nullo con @CheckResult, aggiungi l'annotazione per chiarire i risultati dei metodi potenzialmente confusi.

Ad esempio, i nuovi sviluppatori Java spesso pensano erroneamente che <String>.trim() rimuova gli spazi vuoti dalla stringa originale. L'annotazione del metodo con i flag @CheckResult viene utilizzata per l'utilizzo di <String>.trim() in cui il chiamante non esegue alcuna azione con il valore restituito del metodo.

L'esempio seguente annota il metodo checkPermissions() per verificare se al valore restituito del metodo viene effettivamente fatto riferimento. Inoltre, denomina il metodo enforcePermission() come metodo da suggerire allo sviluppatore in sostituzione:

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

Annotazioni CallSuper

Utilizza l'annotazione @CallSuper per confermare che un metodo di override chiama la superimplementazione del metodo.

L'esempio seguente annota il metodo onCreate() per garantire che qualsiasi implementazione del metodo di override chiami super.onCreate():

Kotlin

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

Java

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

Annotazioni Typedef

Le annotazioni Typedef controllano se un determinato parametro, valore restituito o campo fa riferimento a un insieme specifico di costanti. Consentono inoltre il completamento del codice in modo da offrire automaticamente le costanti consentite.

Utilizza le annotazioni @IntDef e @StringDef per creare annotazioni enumerate di set di numeri interi e di stringhe al fine di convalidare altri tipi di riferimenti di codice.

Le annotazioni Typedef utilizzano @interface per dichiarare il nuovo tipo di annotazione enumerata. Le annotazioni @IntDef e @StringDef, insieme a @Retention, annotano la nuova annotazione e sono necessarie per definire il tipo enumerato. L'annotazione @Retention(RetentionPolicy.SOURCE) indica al compilatore di non archiviare i dati dell'annotazione enumerata nel file .class.

L'esempio seguente mostra i passaggi per creare un'annotazione che verifica se un valore passato come parametro del metodo fa riferimento a una delle costanti definite:

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);
}

Quando crei questo codice, viene generato un avviso se il parametro mode non fa riferimento a una delle costanti definite (NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST o NAVIGATION_MODE_TABS).

Combina @IntDef e @IntRange per indicare che un numero intero può essere un determinato insieme di costanti o un valore all'interno di un intervallo.

Attiva la combinazione di costanti e flag

Se gli utenti possono combinare le costanti consentite con un flag (ad esempio |, &, ^ e così via), puoi definire un'annotazione con un attributo flag per verificare se un parametro o un valore restituito faccia riferimento a un pattern valido.

L'esempio seguente crea l'annotazione DisplayOptions con un elenco di costanti DISPLAY_ valide:

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 {}

...

Quando crei un codice con un flag di annotazione, viene generato un avviso se il parametro decorato o il valore restituito non fa riferimento a un pattern valido.

Mantieni annotazione

L'annotazione @Keep garantisce che una classe o un metodo annotato non venga rimosso quando il codice viene minimizzato in fase di creazione. Questa annotazione in genere viene aggiunta ai metodi e alle classi a cui si accede tramite la riflessione per evitare che il compilatore consideri il codice come inutilizzato.

Attenzione : le classi e i metodi che annotati utilizzando @Keep vengono sempre visualizzati nell'APK dell'app, anche se non fai mai riferimento a queste classi e metodi all'interno della logica dell'app.

Per ridurre le dimensioni della tua app, valuta se è necessario conservare ogni annotazione @Keep nell'app. Se usi la riflessione per accedere a una classe o a un metodo annotati, utilizza un condizionale -if nelle regole di ProGuard, specificando la classe che effettua le chiamate alla riflessione.

Per ulteriori informazioni su come minimizzare il codice e specificare quale codice non deve essere rimosso, consulta la pagina Ridurre, offuscare e ottimizzare l'app.

Annotazioni sulla visibilità del codice

Utilizza le seguenti annotazioni per indicare la visibilità di parti specifiche del codice, come metodi, classi, campi o pacchetti.

Rendi visibile il codice per i test

L'annotazione @VisibleForTesting indica che un metodo annotato è più visibile del solito necessario per renderlo testabile. Questa annotazione ha un argomento facoltativo otherwise che ti consente di indicare la visibilità del metodo se non fosse necessario renderlo visibile per i test. Lint utilizza l'argomento otherwise per applicare la visibilità prevista.

Nell'esempio seguente, myMethod() solitamente è private, ma è package-private per i test. Con la designazione VisibleForTesting.PRIVATE, lint visualizza un messaggio se questo metodo viene chiamato dall'esterno del contesto consentito dall'accesso private, ad esempio da un'altra unità di compilazione.

Kotlin

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

Java

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

Puoi anche specificare @VisibleForTesting(otherwise = VisibleForTesting.NONE) per indicare che un metodo esiste solo per i test. Questo modulo equivale all'utilizzo di @RestrictTo(TESTS). Entrambi eseguono lo stesso controllo del lint.

Limita un'API

L'annotazione @RestrictTo indica che l'accesso all'API annotata (pacchetto, classe o metodo) è limitato, come segue:

Sottoclassi

Utilizza il modulo di annotazione @RestrictTo(RestrictTo.Scope.SUBCLASSES) per limitare l'accesso API solo alle sottoclassi.

Solo le classi che estendono la classe annotata possono accedere a questa API. Il modificatore Java protected non è abbastanza restrittivo, perché consente l'accesso da classi non correlate all'interno dello stesso pacchetto. Inoltre, in alcuni casi potresti voler lasciare un metodo public per flessibilità futura, perché non potrai mai creare un metodo protected e con override in precedenza public, ma desideri fornire un suggerimento per indicare che la classe è destinata a essere utilizzata all'interno della classe o solo dalle sottoclassi.

Librerie

Utilizza il modulo di annotazione @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) per limitare l'accesso API solo alle tue librerie.

Solo il tuo codice libreria può accedere all'API annotata. In questo modo non solo puoi organizzare il codice in qualsiasi gerarchia di pacchetti, ma puoi anche condividerlo tra un gruppo di librerie correlate. Questa opzione è già disponibile per le librerie Jetpack che hanno molto codice di implementazione non destinato all'uso esterno, ma che deve essere public per condividerlo tra le varie librerie Jetpack complementari.

Test

Utilizza il modulo di annotazione @RestrictTo(RestrictTo.Scope.TESTS) per impedire ad altri sviluppatori di accedere alle tue API di test.

Solo il codice di test può accedere all'API annotata. In questo modo impedisci ad altri sviluppatori di utilizzare le API per lo sviluppo che intendi solo per test.