Codeüberprüfung mit Anmerkungen verbessern

Codeprüfungstools wie Lint können Ihnen helfen, Probleme zu finden und Ihren Code zu verbessern, aber Prüftools können nur so viel ableiten. Android-Ressourcen-IDs verwenden beispielsweise ein int, um Strings, Grafiken, Farben und andere Ressourcentypen zu identifizieren, sodass Prüftools nicht erkennen können, ob Sie eine Stringressource angegeben haben, für die Sie eigentlich eine Farbe festlegen sollten. Das bedeutet, dass Ihre App möglicherweise falsch gerendert oder überhaupt nicht ausgeführt wird, selbst wenn Sie die Codeprüfung verwenden.

Mit Annotationen können Sie Tools für die Codeprüfung wie Lint Hinweise zur Verfügung stellen, um diese subtileren Codeprobleme zu erkennen. Anmerkungen werden als Metadaten-Tags hinzugefügt, die Sie an Variablen, Parameter und Rückgabewerte anhängen, um Rückgabewerte von Methoden, übergebene Parameter, lokale Variablen und Felder zu untersuchen. In Verbindung mit Code-Inspektionstools können Annotationen dabei helfen, Probleme wie Nullzeigerausnahmen und Konflikte bei Ressourcentypen zu erkennen.

Android unterstützt eine Vielzahl von Anmerkungen über die Jetpack Annotations Library. Sie können über das Paket androidx.annotation auf die Bibliothek zugreifen.

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

Anmerkungen zum Projekt hinzufügen

Um Annotationen in Ihrem Projekt zu aktivieren, fügen Sie die androidx.annotation:annotation-Abhängigkeit zu Ihrer Bibliothek oder App hinzu. Alle hinzugefügten Annotationen werden geprüft, wenn Sie eine Codeüberprüfung oder eine lint-Aufgabe ausführen.

Abhängigkeit der Jetpack-Anmerkungsbibliothek hinzufügen

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

Kotlin

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

Groovig

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

Wenn Sie Annotationen in Ihrem eigenen Bibliotheksmodul verwenden, sind diese in der Datei annotations.zip als Teil des Android Archive-Artefakts (AAR) im XML-Format enthalten. Durch das Hinzufügen der Abhängigkeit androidx.annotation entsteht keine Abhängigkeit für nachgelagerte Nutzer Ihrer Bibliothek.

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 Annotationen im Jetpack-Repository finden Sie entweder in der Referenz zur Jetpack-Annotationsbibliothek oder verwenden Sie die Funktion zur automatischen Vervollständigung, um die verfügbaren Optionen für die import androidx.annotation.-Anweisung aufzurufen.

Codeprüfungen ausführen

Wählen Sie im Menü Analysieren > Code untersuchen aus, um in Android Studio eine Codeprüfung zu starten, die Annotationen und automatische Lint-Prüfung umfasst. Android Studio zeigt Konfliktmeldungen an, um potenzielle Probleme zu melden, 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. Dies kann nützlich sein, wenn Sie Probleme mit einem Continuous-Integration-Server melden. Die Aufgabe lint erzwingt jedoch keine Annotationen für Nullwerte (wird im folgenden Abschnitt beschrieben). Dies geschieht nur in Android Studio. Weitere Informationen zum Aktivieren und Ausführen von Lint-Prüfungen finden Sie unter Code mit Lint-Prüfungen verbessern.

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

Annotationen von Null-NULL-Werten

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

Fügen Sie die Annotationen @Nullable und @NonNull hinzu, um die NULL-Werte einer bestimmten Variablen, eines Parameters oder eines Rückgabewerts zu prüfen. Die Annotation @Nullable gibt eine Variable, einen Parameter oder einen Rückgabewert an, die bzw. 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 Annotation @NonNull übergeben wird, die an diesen Parameter angehängt ist, wird beim Erstellen des Codes eine Warnung generiert, die auf einen Nicht-Null-Konflikt hinweist. Wenn außerdem versucht wird, auf das Ergebnis einer mit @Nullable gekennzeichneten Methode zu verweisen, ohne vorher zu prüfen, ob das Ergebnis null ist, wird eine Null-Warnung ausgelöst. Verwenden Sie @Nullable nur dann für den Rückgabewert einer Methode, wenn bei jeder Verwendung der Methode explizit eine Nullprüfung durchgeführt werden muss.

Das folgende Beispiel zeigt die Null-Zulässigkeit in Aktion. Im Kotlin-Beispielcode wird die Annotation @NonNull nicht genutzt, da sie dem generierten Bytecode automatisch hinzugefügt wird, wenn ein Typ angegeben wird, der keine Nullwerte zulässt. Im Java-Beispiel wird mithilfe der Annotation @NonNull für die Parameter context und attrs geprüft, 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 Durchführung einer Null-Zulässigkeitsanalyse, um automatisch Annotationen abzuleiten und in Ihren Code einzufügen. Eine Null-Zulässigkeitsanalyse scannt die Verträge in den Methodenhierarchien in Ihrem Code, um Folgendes zu erkennen:

  • Aufrufmethoden, die null zurückgeben können.
  • Methoden, die nicht null zurückgeben sollen.
  • 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.

Die Analyse fügt dann automatisch die entsprechenden Null-Annotationen an den erkannten Orten ein.

Wählen Sie zum Ausführen einer Null-Zulässigkeitsanalyse in Android Studio Analysieren > Nullwerte ableiten aus. Android Studio fügt die Android-Anmerkungen @Nullable und @NonNull in erkannten Positionen in Ihrem Code ein. Nach dem Ausführen einer Nullanalyse empfiehlt es sich, die injizierten Annotationen zu überprüfen.

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

Ressourcenanmerkungen

Das Prüfen 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 String verweist, kann an den erwarteten Referenztyp von int übergeben werden, verweist jedoch auf einen anderen Ressourcentyp wie eine R.string-Ressource.

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

Kotlin

abstract fun setTitle(@StringRes resId: Int)

Java

public abstract void setTitle(@StringRes int resId)

Bei 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 der Parameter mehrere Ressourcentypen unterstützt, können Sie einem Parameter mehrere Ressourcentyp-Annotationen hinzufügen. Mit @AnyRes geben Sie an, dass der annotierte Parameter ein beliebiger Typ von R-Ressource sein kann.

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

Thread-Anmerkungen

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

Die Build-Tools behandeln die @MainThread- und @UiThread-Annotationen als austauschbar, sodass Sie @UiThread-Methoden über @MainThread-Methoden aufrufen können und umgekehrt. Bei Systemanwendungen mit mehreren Ansichten in verschiedenen Threads kann ein UI-Thread vom Hauptthread jedoch abweichen. Daher sollten Sie Methoden, die der Ansichtshierarchie einer Anwendung zugeordnet sind, mit @UiThread annotieren und nur Methoden, die dem Lebenszyklus einer Anwendung zugeordnet sind, mit @MainThread.

Wenn für alle Methoden in einer Klasse die gleiche Threading-Anforderung gilt, können Sie der Klasse eine einzelne Thread-Annotation hinzufügen, um zu überprüfen, ob alle Methoden in der Klasse vom selben Thread-Typ aus aufgerufen werden.

Thread-Annotationen werden häufig verwendet, um zu prüfen, ob mit @WorkerThread annotierte Methoden oder Klassen nur aus einem geeigneten Hintergrundthread aufgerufen werden.

Annotationen zur Wertbeschränkung

Verwenden Sie die Annotationen @IntRange, @FloatRange und @Size, um die Werte der übergebenen 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 liegen.

Die Annotation @IntRange prüft, ob ein ganzzahliger oder langer Parameterwert innerhalb eines angegebenen Bereichs liegt. Im folgenden Beispiel muss der Parameter alpha eine Ganzzahl 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) { ... }

Die Annotation @FloatRange prüft, ob ein Gleitkomma- oder Double-Parameterwert innerhalb eines bestimmten Gleitkommabereichs liegt. Im folgenden Beispiel muss der Parameter alpha eine Gleitkommazahl zwischen 0,0 und 1,0 enthalten:

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 Annotation @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)
  • Maximalgröße, z. B. @Size(max=2)
  • Genaue Größe, zum Beispiel @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 leer ist, und @Size(3) prüft, ob ein Array genau drei Werte enthält.

Im folgenden Beispiel muss das Array location mindestens ein Element enthalten:

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

Annotationen zu Berechtigungen

Validieren Sie mit der Annotation @RequiresPermission die Berechtigungen des Aufrufers einer Methode. Mit dem Attribut anyOf können Sie nach einer einzelnen Berechtigung aus einer Liste gültiger Berechtigungen suchen. Mit dem Attribut allOf kannst du prüfen, ob eine Reihe von Berechtigungen vorhanden ist. 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;

Für das folgende Beispiel muss der Aufrufer der Methode copyImageFile() sowohl Lesezugriff auf 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) {
    //...
}

Für Berechtigungen für Intents platzieren Sie die Berechtigungsanforderung in das Stringfeld, das den Namen der Intent-Aktion definiert:

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

Fassen Sie für Berechtigungen für Inhaltsanbieter, die separate Berechtigungen für Lese- und Schreibzugriff benötigen, jede Berechtigungsanforderung in eine @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 Datenflussanalyse durch, um zu prüfen, ob das an die Methode übergebene Argument @RequiresPermission-Annotationen enthält. Anschließend erzwingt sie alle vorhandenen Annotationen des Parameters in der Methode selbst. Im Beispiel startActivity(Intent) verursachen Anmerkungen in der Klasse Intent die resultierenden Warnungen bei einer ungültigen Verwendung von startActivity(Intent), wenn ein Intent ohne die entsprechenden Berechtigungen an die Methode übergeben wird (siehe Abbildung 1).

Abbildung 1: Die von einer indirekten 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";

Sie können bei Bedarf @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 jede Methode ohne Leerzeichen mit @CheckResult zu annotieren, fügen Sie die Annotation hinzu, um die Ergebnisse potenziell verwirrender Methoden zu verdeutlichen.

Neue Java-Entwickler denken beispielsweise oft fälschlicherweise, dass <String>.trim() Leerzeichen im ursprünglichen String entfernt. Wenn die Methode mit @CheckResult-Flags annotiert wird, wird <String>.trim() verwendet, wobei der Aufrufer nichts mit dem Rückgabewert der Methode tut.

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

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 überprüfen, ob eine Überschreibungsmethode die Superimplementierung der Methode aufruft.

Im folgenden Beispiel wird die Methode onCreate() annotiert, damit bei jeder überschreibenden Methodenimplementierung super.onCreate() aufgerufen wird:

Kotlin

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

Java

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

Typedef-Annotationen

Typedef-Annotationen prüfen, ob ein bestimmter Parameter, Rückgabewert oder ein Feld auf einen bestimmten Satz von Konstanten verweist. Sie ermöglichen auch die Codevervollständigung, um die zulässigen Konstanten automatisch bereitzustellen.

Mit den Annotationen @IntDef und @StringDef können Sie Enum-Annotationen mit 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 annotieren gemeinsam mit @Retention die neue Annotation und sind erforderlich, um den Aufzählungstyp zu definieren. Die Annotation @Retention(RetentionPolicy.SOURCE) weist den Compiler an, die Aufzählungsdaten 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);
}

Wenn Sie diesen Code erstellen, wird eine Warnung generiert, wenn der mode-Parameter 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.

Kombination von Konstanten mit Flags aktivieren

Wenn Nutzer die zulässigen Konstanten mit einem Flag kombinieren können (z. B. |, & oder ^), lässt sich eine Annotation mit einem flag-Attribut definieren. So lässt sich 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 Annotations-Flag erstellen, wird eine Warnung generiert, wenn der dekorierte Parameter oder Rückgabewert nicht auf ein 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 in der Regel Methoden und Klassen hinzugefügt, auf die über Reflexion zugegriffen wird. So wird verhindert, dass der Compiler den Code als ungenutzt behandelt.

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

Überlege, ob du jede @Keep-Annotation in der App beibehalten musst. Wenn du mithilfe der Reflexion auf eine annotierte Klasse oder Methode zugreifen möchtest, verwende eine -if-Bedingung in deinen ProGuard-Regeln und lege die Klasse fest, die die Reflexionsaufrufe durchführt.

Weitere Informationen zum Komprimieren von Code und zum Angeben, welcher Code nicht entfernt werden soll, finden Sie unter Anwendung verkleinern, verschleiern und optimieren.

Anmerkungen zur Codesichtbarkeit

Verwenden Sie die folgenden Annotationen, um die Sichtbarkeit bestimmter Teile des Codes festzulegen, z. B. Methoden, Klassen, Felder oder Pakete.

Code zum Testen sichtbar machen

Die Annotation @VisibleForTesting gibt an, dass eine annotierte Methode besser sichtbar 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 nicht für Tests sichtbar wäre. Lint verwendet das Argument otherwise, um die gewünschte Sichtbarkeit zu erzwingen.

Im folgenden Beispiel ist myMethod() normalerweise private, für Tests ist es aber package-private. Mit der Kennzeichnung VisibleForTesting.PRIVATE zeigt Lint eine Meldung an, wenn diese Methode von außerhalb des für den private-Zugriff erlaubten Kontexts aufgerufen wird, z. B. aus 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 für Tests vorhanden ist. Dieses Formular ist das gleiche wie das Verwenden von @RestrictTo(TESTS). Beide führen dieselbe 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 Annotationsformular @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 nicht in Beziehung stehenden Klassen innerhalb desselben Pakets ermöglicht. Es gibt auch Fälle, in denen Sie für zukünftige Flexibilität die Methode public beibehalten möchten, da Sie nie eine zuvor protected und überschriebene Methode public erstellen können, aber einen Hinweis darauf geben möchten, dass die Klasse nur für Nutzungen innerhalb der Klasse oder von Unterklassen vorgesehen ist.

Bibliotheken

Verwenden Sie das Annotationsformular @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 ihn auch mit einer Gruppe zusammengehöriger Bibliotheken teilen. Diese Option ist bereits für die Jetpack-Bibliotheken mit viel Implementierungscode verfügbar, der nicht für die externe Verwendung bestimmt ist, aber public sein muss, um ihn mit den verschiedenen komplementären Jetpack-Bibliotheken teilen zu können.

Testen

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

Nur Testcode kann auf die annotierte API zugreifen. So wird verhindert, dass andere Entwickler APIs für die Entwicklung verwenden, die Sie nur zu Testzwecken verwenden möchten.