Codeüberprüfung mit Anmerkungen verbessern

Mit Code-Inspektionstools wie lint können Sie Probleme finden und Ihren Code verbessern, aber Inspektionstools können nur einen bestimmten Teil davon ableiten. Android-Ressourcen-IDs verwenden beispielsweise ein int, um Strings, Grafiken, Farben und andere Ressourcentypen zu identifizieren. Prüftools können also nicht feststellen, ob Sie eine Stringressource angegeben haben, für die Sie eine Farbe angeben sollten. Das bedeutet, dass Ihre Anwendung möglicherweise nicht korrekt gerendert wird oder überhaupt nicht ausgeführt wird, selbst wenn Sie die Codeprüfung verwenden.

Mit Annotationen können Sie Hinweise für Codeinspektionstools wie Lint angeben, um diese kleineren Codeprobleme zu erkennen. Annotationen werden als Metadaten-Tags hinzugefügt, die Sie an Variablen, Parameter und Rückgabewerte anhängen, um Methodenrückgabewerte, übergebene Parameter, lokale Variablen und Felder zu prüfen. Wenn Annotationen mit Code-Inspektionstools verwendet werden, können Sie Probleme wie Null-Zeiger-Ausnahmen und Ressourcentypkonflikte leichter erkennen.

Android unterstützt eine Vielzahl von Annotationen über die Jetpack-Annotationsbibliothek. Der Zugriff auf die Bibliothek erfolgt über das Paket androidx.annotation.

Hinweis:Wenn ein Modul eine Abhängigkeit von einem Annotationsprozessor hat, müssen Sie entweder die Abhängigkeitskonfiguration kapt oder ksp für Kotlin oder die annotationProcessor-Abhängigkeitskonfiguration für Java verwenden, um diese Abhängigkeit hinzuzufügen.

Anmerkungen zum Projekt hinzufügen

Wenn Sie Annotationen in Ihrem Projekt aktivieren möchten, fügen Sie Ihrer Bibliothek oder App die Abhängigkeit androidx.annotation:annotation hinzu. Alle hinzugefügten Annotationen werden bei der Codeprüfung oder lint-Aufgabe geprüft.

Abhängigkeit der Jetpack-Annotations-Bibliothek hinzufügen

Die Jetpack-Annotationsbibliothek wird im Maven-Repository von Google veröffentlicht. Fügen Sie die folgende Zeile in den Block dependencies der Datei build.gradle oder build.gradle.kts ein, um Ihrem Projekt die Jetpack Anotations-Bibliothek hinzuzufügen:

Kotlin

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

Cool

dependencies {
    implementation 'androidx.annotation:annotation:1.8.0'
}
Klicken Sie dann in der Symbolleiste oder in der angezeigten Synchronisierungsbenachrichtigung auf Jetzt synchronisieren.

Wenn du Anmerkungen in deinem eigenen Bibliotheksmodul verwendest, sind diese in der Datei annotations.zip als Teil des Android Archive-Artefakts (AAR) im XML-Format enthalten. Das Hinzufügen der androidx.annotation-Abhängigkeit bringt keine Abhängigkeit für nachgelagerte Nutzer Ihrer Bibliothek mit sich.

Hinweis:Wenn Sie andere Jetpack-Bibliotheken verwenden, müssen Sie die Abhängigkeit androidx.annotation möglicherweise nicht hinzufügen. Da viele andere Jetpack-Bibliotheken von der Annotationsbibliothek abhängen, haben Sie möglicherweise bereits Zugriff auf die Annotationen.

Eine vollständige Liste der im Jetpack-Repository enthaltenen Annotationen finden Sie in der Referenz zur Jetpack-Annotationsbibliothek. Sie können auch die Funktion zur automatischen Vervollständigung verwenden, um die verfügbaren Optionen für die Anweisung import androidx.annotation. aufzurufen.

Codeprüfungen ausführen

Um eine Codeinspektion in Android Studio zu starten, die das Validieren von Annotationen und die automatische Lint-Prüfung umfasst, wählen Sie im Menü Analysieren > Code prüfen aus. Android Studio zeigt Konfliktmeldungen an, um potenzielle Probleme zu kennzeichnen, bei denen Ihr Code mit Anmerkungen in Konflikt steht, und um mögliche Lösungen vorzuschlagen.

Sie können Annotationen auch erzwingen, indem Sie die Aufgabe lint über die Befehlszeile ausführen. Obwohl dies nützlich sein kann, um Probleme mit einem Continuous-Integrations-Server zu melden, erzwingt die Aufgabe lint keine Anmerkungen zu Nullwerten (wie im folgenden Abschnitt beschrieben). Dies ist nur in Android Studio möglich. Weitere Informationen zum Aktivieren und Ausführen von Lint-Prüfungen finden Sie unter Code mit Lint-Prüfungen verbessern.

Auch wenn Annotationskonflikte Warnungen generieren, verhindern diese Warnungen nicht, dass Ihre Anwendung kompiliert wird.

Annotationen von Null-Werten

Annotationen von Null-Werten können in Java-Code hilfreich sein, um zu erzwingen, ob Werte null sein können. Sie sind im Kotlin-Code weniger nützlich, da Kotlin-Regeln für die Null-Zulässigkeit eingebaut sind, die beim Kompilieren erzwungen werden.

Fügen Sie die Annotationen @Nullable und @NonNull hinzu, um die Nullstufe einer bestimmten Variablen, eines bestimmten Parameters oder eines Rückgabewerts zu prüfen. Die Annotation @Nullable gibt eine Variable, einen Parameter oder einen Rückgabewert an, der null sein kann. @NonNull gibt eine Variable, einen Parameter oder einen Rückgabewert an, der nicht null sein darf.

Wenn beispielsweise eine lokale Variable, die einen Nullwert enthält, als Parameter an eine Methode mit der Anmerkung @NonNull an diesen Parameter übergeben wird, generiert das Erstellen des Codes eine Warnung, die auf einen Konflikt, der nicht null ist, hinweist. Wenn versucht wird, auf das Ergebnis einer Methode zu verweisen, die mit @Nullable markiert ist, ohne zuerst zu prüfen, ob das Ergebnis null ist, wird eine Warnung vor dem NULL-Wert generiert. Verwenden Sie @Nullable nur für den Rückgabewert einer Methode, wenn jede Verwendung der Methode explizit auf null geprüft werden muss.

Das folgende Beispiel zeigt die Null-Zulässigkeit in der Praxis. Im Kotlin-Beispielcode wird die Annotation @NonNull nicht verwendet, da sie dem generierten Bytecode automatisch hinzugefügt wird, wenn ein Typ angegeben wird, der keine Nullwerte zulässt. Im Java-Beispiel wird die Annotation @NonNull für die Parameter context und attrs verwendet, um zu prüfen, ob die übergebenen Parameterwerte nicht Null sind. Außerdem wird geprüft, ob die Methode onCreateView() selbst nicht null zurückgibt:

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 der Null-Zulässigkeit

Android Studio unterstützt die Ausführung einer Analyse zur Null-Zulässigkeit, um Annotationen zur Null-Zulässigkeit automatisch abzuleiten und in Ihren Code einzufügen. Bei einer Analyse der Null-Zulässigkeit werden die Verträge in den Methodenhierarchien Ihres Codes gescannt, um Folgendes zu erkennen:

  • Aufrufen von Methoden, die null zurückgeben können.
  • Methoden, die nicht null zurückgeben sollten.
  • Variablen wie Felder, lokale Variablen und Parameter, die null sein können.
  • Variablen wie Felder, lokale Variablen und Parameter, die keinen Nullwert enthalten dürfen.

Bei der Analyse werden dann automatisch die entsprechenden Null-Annotationen an den erkannten Positionen eingefügt.

Wählen Sie zum Ausführen einer Analyse der Null-Zulässigkeit in Android Studio Analysieren > Nullität ableiten aus. Android Studio fügt die Android-Annotationen @Nullable und @NonNull an erkannten Stellen in Ihrem Code ein. Nachdem Sie eine Null-Analyse ausgeführt haben, sollten Sie die eingefügten Annotationen überprüfen.

Hinweis:Wenn Sie Annotationen zu Nullwerten hinzufügen, schlägt die automatische Vervollständigung möglicherweise die IntelliJ-Annotationen @Nullable und @NotNull anstelle der Android-Null-Annotationen vor. Die entsprechende Bibliothek kann dann automatisch importiert werden. Die Lint-Prüfung in Android Studio sucht jedoch nur nach den Android-Null-Annotationen. Achten Sie beim Überprüfen Ihrer Annotationen darauf, dass Ihr Projekt die Android-Null-Annotationen verwendet, damit Sie während der Codeprüfung von der Lint-Prüfung ordnungsgemäß benachrichtigt werden.

Ressourcenanmerkungen

Die Validierung von Ressourcentypen kann nützlich sein, da Android-Verweise auf Ressourcen wie drawable- und string-Ressourcen als Ganzzahlen übergeben werden.

Code, der erwartet, dass ein Parameter auf einen bestimmten Ressourcentyp wie etwa String verweist, kann an den erwarteten Referenztyp von int übergeben werden, tatsächlich aber auf einen anderen Ressourcentyp wie etwa eine R.string-Ressource verweisen.

Fügen Sie beispielsweise @StringRes-Annotationen hinzu, um zu prüfen, ob ein Ressourcenparameter einen Verweis R.string enthält, wie hier gezeigt:

Kotlin

abstract fun setTitle(@StringRes resId: Int)

Java

public abstract void setTitle(@StringRes int resId)

Während der Codeprüfung generiert die Annotation eine Warnung, wenn im Parameter kein R.string-Verweis übergeben wird.

Annotationen für andere Ressourcentypen wie @DrawableRes, @DimenRes, @ColorRes und @InterpolatorRes können mit demselben Annotationsformat hinzugefügt und während der Codeprüfung ausgeführt werden.

Wenn Ihr Parameter mehrere Ressourcentypen unterstützt, können Sie einem bestimmten Parameter mehrere Ressourcentypanmerkungen hinzufügen. Verwenden Sie @AnyRes, um anzugeben, dass der annotierte Parameter ein beliebiger Typ von R-Ressource sein kann.

Sie können zwar mit @ColorRes angeben, dass ein Parameter eine Farbressource sein soll, eine Farbzahl im Format RRGGBB oder AARRGGBB wird jedoch nicht als Farbressource erkannt. Verwenden Sie stattdessen die Annotation @ColorInt, um anzugeben, dass ein Parameter eine Ganzzahl sein muss. Die Build-Tools melden falschen Code, der eine Farbressourcen-ID wie android.R.color.black anstelle einer Farbganzzahl an Methoden mit Anmerkungen übergibt.

Thread-Annotationen

Thread-Annotationen prüfen, ob eine Methode von einem bestimmten Thread-Typ aufgerufen wird. Die folgenden Threadanmerkungen werden unterstützt:

Die Build-Tools behandeln die Annotationen @MainThread und @UiThread als austauschbar, sodass Sie @UiThread-Methoden von @MainThread-Methoden aufrufen können und umgekehrt. Im Fall von Systemanwendungen mit mehreren Ansichten in verschiedenen Threads ist es jedoch möglich, dass sich ein UI-Thread vom Hauptthread unterscheidet. Daher sollten Sie Methoden, die mit der Ansichtshierarchie einer App verknüpft sind, mit @UiThread annotieren und nur Methoden, die mit dem Lebenszyklus einer App verknüpft sind, mit @MainThread annotieren.

Wenn alle Methoden in einer Klasse dieselben Threading-Anforderungen haben, können Sie der Klasse eine einzelne Thread-Annotation hinzufügen, um zu prüfen, ob alle Methoden in der Klasse vom selben Thread-Typ aufgerufen werden.

Thread-Annotationen werden häufig verwendet, um zu validieren, dass mit @WorkerThread annotierte Methoden oder Klassen nur aus einem entsprechenden Hintergrundthread aufgerufen werden.

Anmerkungen zur Wertbeschränkung

Verwenden Sie die Annotationen @IntRange, @FloatRange und @Size, um die Werte übergebener Parameter zu validieren. Sowohl @IntRange als auch @FloatRange sind am nützlichsten, wenn sie auf Parameter angewendet werden, bei denen Nutzer wahrscheinlich einen falschen Bereich erhalten.

Die Annotation @IntRange prüft, ob ein ganzzahliger oder langer Parameterwert innerhalb eines angegebenen Bereichs liegt. Im folgenden Beispiel muss der Parameter alpha einen ganzzahligen Wert zwischen 0 und 255 enthalten:

Kotlin

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

Java

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

Mit der Annotation @FloatRange wird geprüft, ob ein Gleitkomma- oder Double-Parameterwert innerhalb eines bestimmten Bereichs von Gleitkommawerten liegt. Im folgenden Beispiel wird angegeben, dass der Parameter alpha eine Gleitkommazahl zwischen 0,0 und 1,0 enthalten muss:

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

Die Anmerkung @Size prüft die Größe einer Sammlung oder eines Arrays oder die Länge eines Strings. Mit der Annotation @Size können die folgenden Qualitäten geprüft werden:

  • Mindestgröße, z. B. @Size(min=2)
  • Maximale Größe, z. B. @Size(max=2)
  • Genaue Größe, z. B. @Size(2)
  • Eine Zahl, deren Größe ein Vielfaches sein muss, z. B. @Size(multiple=2)

Beispielsweise prüft @Size(min=1), ob eine Sammlung nicht leer ist, und @Size(3) validiert, dass ein Array genau drei Werte enthält.

Das folgende Beispiel zeigt, dass das Array location mindestens ein Element enthalten muss:

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

Berechtigungsanmerkungen

Validieren Sie mit der Annotation @RequiresPermission die Berechtigungen des Aufrufers einer Methode. Mit dem Attribut anyOf können Sie aus einer Liste gültiger Berechtigungen nach einer einzelnen Berechtigung suchen. Verwenden Sie das Attribut allOf, um eine Reihe von Berechtigungen zu prüfen. Im folgenden Beispiel wird die Methode setWallpaper() annotiert, um anzugeben, dass der Aufrufer der Methode die Berechtigung permission.SET_WALLPAPERS haben muss:

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;

Im folgenden Beispiel muss der Aufrufer der Methode copyImageFile() sowohl Lesezugriff auf den externen Speicher als auch Lesezugriff auf Standortmetadaten im kopierten Bild haben:

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

Um Berechtigungen für Intents zu erhalten, fügen Sie die Berechtigungsanforderung in das Stringfeld ein, in dem der Name der Intent-Aktion definiert wird:

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

Schließen Sie bei Berechtigungen für Contentanbieter, die separate Berechtigungen für den Lese- und Schreibzugriff benötigen, jede Berechtigungsanforderung in einer @RequiresPermission.Read- oder @RequiresPermission.Write-Annotation ein:

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

Indirekte Berechtigungen

Wenn eine Berechtigung von dem spezifischen Wert abhängt, der für den Parameter einer Methode angegeben wurde, verwenden Sie @RequiresPermission für den Parameter selbst, ohne die spezifischen Berechtigungen aufzulisten. Die Methode startActivity(Intent) verwendet beispielsweise eine indirekte Berechtigung für den Intent, der an die Methode übergeben wird:

Kotlin

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

Java

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

Wenn Sie indirekte Berechtigungen verwenden, führen die Build-Tools eine Dataflow-Analyse durch, um zu prüfen, ob das an die Methode übergebene Argument @RequiresPermission-Annotationen enthält. Anschließend werden alle vorhandenen Annotationen aus dem Parameter für die Methode selbst erzwungen. Im Beispiel startActivity(Intent) verursachen Anmerkungen in der Klasse Intent die entsprechenden Warnungen bei ungültigen startActivity(Intent)-Verwendungen, wenn ein Intent ohne die entsprechenden Berechtigungen an die Methode übergeben wird (siehe Abbildung 1).

Abbildung 1: Die durch eine indirekte Berechtigungsannotation in der Methode startActivity(Intent) generierte Warnung.

Die Build-Tools generieren die Warnung für startActivity(Intent) aus der Annotation zum entsprechenden Intent-Aktionsnamen in der Klasse 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";

Bei Bedarf können Sie @RequiresPermission durch @RequiresPermission.Read oder @RequiresPermission.Write ersetzen, wenn Sie den Parameter einer Methode annotieren. Für indirekte Berechtigungen sollte @RequiresPermission jedoch nicht in Verbindung mit den Annotationen der Lese- oder Schreibberechtigungen verwendet werden.

Anmerkungen zu Rückgabewerten

Mit der Annotation @CheckResult können Sie prüfen, ob das Ergebnis oder der Rückgabewert einer Methode tatsächlich verwendet wird. Anstatt alle nicht ungültigen Methoden mit @CheckResult zu annotieren, fügen Sie die Annotation hinzu, um die Ergebnisse potenziell verwirrender Methoden zu verdeutlichen.

Neue Java-Entwickler glauben beispielsweise oft, dass durch <String>.trim() Leerzeichen aus dem ursprünglichen String entfernt werden. Beim Annotieren der Methode mit @CheckResult-Flags wird <String>.trim() verwendet, wobei der Aufrufer nichts mit dem Rückgabewert der Methode ausführt.

Im folgenden Beispiel wird die Methode checkPermissions() annotiert, um zu prüfen, ob auf den Rückgabewert der Methode tatsächlich verwiesen wird. Außerdem wird die Methode enforcePermission() als Methode benannt, die dem Entwickler als Ersatz vorgeschlagen werden soll:

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

CallSuper-Anmerkungen

Mit der Annotation @CallSuper können Sie prüfen, ob eine Überschreibungsmethode die Superimplementierung der Methode aufruft.

Im folgenden Beispiel wird die Methode onCreate() annotiert, damit alle Implementierungen mit überschreibender Methoden super.onCreate() aufrufen:

Kotlin

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

Java

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

Typedef-Anmerkungen

Mit Typedef-Annotationen wird geprüft, ob ein bestimmter Parameter, Rückgabewert oder Feld auf eine bestimmte Gruppe von Konstanten verweist. Sie ermöglichen auch die Codevervollständigung, um automatisch die zulässigen Konstanten anzubieten.

Mit den Annotationen @IntDef und @StringDef können Sie Aufzählungsannotationen von Ganzzahl- und Stringsätzen erstellen, um andere Arten von Codeverweisen zu validieren.

Typedef-Annotationen verwenden @interface, um den neuen Enum-Annotationstyp zu deklarieren. Die Annotationen @IntDef und @StringDef sowie @Retention annotieren die neue Annotation und sind erforderlich, um den Aufzählungstyp zu definieren. Die Annotation @Retention(RetentionPolicy.SOURCE) weist den Compiler an, die aufgezählten Annotationsdaten nicht in der Datei .class zu speichern.

Das folgende Beispiel zeigt die Schritte zum Erstellen einer Annotation, die prüft, ob ein als Methodenparameter übergebener Wert auf eine der definierten Konstanten verweist:

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

Beim Erstellen dieses Codes wird eine Warnung generiert, wenn der Parameter mode nicht auf eine der definierten Konstanten (NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST oder NAVIGATION_MODE_TABS) verweist.

Kombinieren Sie @IntDef und @IntRange, um anzugeben, dass eine Ganzzahl entweder ein bestimmter Satz von Konstanten oder ein Wert innerhalb eines Bereichs sein kann.

Kombinieren von Konstanten mit Flags aktivieren

Wenn Nutzer die zulässigen Konstanten mit einem Flag kombinieren können (z. B. |, &, ^ usw.), können Sie eine Annotation mit einem flag-Attribut definieren, um zu prüfen, ob ein Parameter oder Rückgabewert auf ein gültiges Muster verweist.

Im folgenden Beispiel wird die Annotation DisplayOptions mit einer Liste gültiger DISPLAY_-Konstanten erstellt:

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

...

Wenn Sie Code mit einem Anmerkungs-Flag erstellen, wird eine Warnung generiert, wenn der dekorierte Parameter oder Rückgabewert auf kein gültiges Muster verweist.

Anmerkung beibehalten

Die Annotation @Keep sorgt dafür, dass eine annotierte Klasse oder Methode nicht entfernt wird, wenn der Code zum Build-Zeitpunkt reduziert wird. Diese Annotation wird normalerweise Methoden und Klassen hinzugefügt, auf die durch Reflexion zugegriffen wird, um zu verhindern, dass der Compiler den Code als nicht verwendet behandelt.

Achtung : Die Klassen und Methoden, die Sie mit @Keep annotieren, werden immer im APK Ihrer App angezeigt, auch wenn Sie in der App-Logik nie auf diese Klassen und Methoden verweisen.

Damit die App klein bleibt, solltest du überlegen, ob du jede @Keep-Anmerkung in deiner App beibehalten musst. Wenn du mithilfe von Reflexion auf eine annotierte Klasse oder Methode zugreifen möchtest, verwende in deinen ProGuard-Regeln eine -if-Bedingung, mit der die Klasse angegeben wird, die die Reflexionsaufrufe durchführt.

Weitere Informationen zum Reduzieren des Codes und zum Angeben, welcher Code nicht entfernt werden soll, findest du unter App verkleinern, verschleiern und optimieren.

Anmerkungen zur Sichtbarkeit von Code

Verwenden Sie die folgenden Annotationen, um die Sichtbarkeit bestimmter Codeabschnitte wie Methoden, Klassen, Felder oder Pakete zu kennzeichnen.

Code für Tests sichtbar machen

Die Annotation @VisibleForTesting gibt an, dass eine annotierte Methode sichtbarer ist als normalerweise erforderlich, um die Methode testbar zu machen. Diese Annotation hat ein optionales otherwise-Argument, mit dem Sie die Sichtbarkeit der Methode festlegen können, wenn sie für Tests nicht sichtbar sein würde. Lint verwendet das Argument otherwise, um die gewünschte Sichtbarkeit zu erzwingen.

Im folgenden Beispiel ist myMethod() normalerweise private, für Tests jedoch package-private. Mit der Kennzeichnung VisibleForTesting.PRIVATE zeigt Lint eine Meldung an, wenn diese Methode außerhalb des Kontexts aufgerufen wird, der für den private-Zugriff zulässig ist, z. B. von einer anderen Kompilierungseinheit.

Kotlin

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

Java

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

Sie können auch @VisibleForTesting(otherwise = VisibleForTesting.NONE) angeben, um anzugeben, dass eine Methode nur zum Testen vorhanden ist. Dieses Formular entspricht der Verwendung von @RestrictTo(TESTS). Beide führen die gleiche Lint-Prüfung durch.

API einschränken

Die Annotation @RestrictTo gibt an, dass der Zugriff auf die annotierte API (Paket, Klasse oder Methode) eingeschränkt ist:

Abgeleitete Klassen

Verwenden Sie das Annotationsform @RestrictTo(RestrictTo.Scope.SUBCLASSES), um den API-Zugriff auf abgeleitete Klassen zu beschränken.

Nur Klassen, die die annotierte Klasse erweitern, können auf diese API zugreifen. Der Java-Modifikator protected ist nicht restriktiv genug, da er den Zugriff von unabhängigen Klassen innerhalb desselben Pakets ermöglicht. Es gibt auch Fälle, in denen Sie die Methode public für zukünftige Flexibilität beibehalten möchten, da Sie nie eine zuvor protected und eine überschriebene Methode public erstellen können, aber einen Hinweis darauf geben möchten, dass die Klasse für Verwendungen innerhalb der Klasse oder nur aus abgeleiteten Klassen vorgesehen ist.

Bibliotheken

Verwenden Sie das Annotationsformat @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX), um den API-Zugriff auf Ihre Bibliotheken zu beschränken.

Nur Ihr Bibliothekscode kann auf die annotierte API zugreifen. Auf diese Weise können Sie Ihren Code nicht nur in einer beliebigen Pakethierarchie organisieren, sondern den Code auch für eine Gruppe verwandter Bibliotheken freigeben. Diese Option ist bereits für die Jetpack-Bibliotheken verfügbar, die viel Implementierungscode enthalten, der nicht für die externe Verwendung bestimmt ist, aber public sein muss, um sie für die verschiedenen komplementären Jetpack-Bibliotheken freizugeben.

Testen

Verwenden Sie das Annotationsformat @RestrictTo(RestrictTo.Scope.TESTS), um zu verhindern, dass andere Entwickler auf Ihre Test-APIs zugreifen.

Nur Testcode kann auf die annotierte API zugreifen. Dadurch wird verhindert, dass andere Entwickler APIs zu Testzwecken verwenden.