Ulepsz inspekcję kodu za pomocą adnotacji

Korzystanie z narzędzi do inspekcji kodu, takich jak lint, może pomóc w wykrywaniu problemów i ulepszaniu kodu, ale narzędzia do inspekcji nie są w stanie wyciągnąć zbyt wielu wniosków. Na przykład identyfikatory zasobów Androida używają wartości int do identyfikowania ciągów znaków, grafik, kolorów i innych typów zasobów, dzięki czemu narzędzia do inspekcji nie mogą stwierdzić, kiedy zdefiniowano zasób ciągu znaków, a kiedy kolor. W takiej sytuacji aplikacja może się nieprawidłowo renderować lub w ogóle nie uruchomić, nawet jeśli przeprowadzisz kontrolę kodu.

Dzięki adnotacjom możesz przekazywać wskazówki narzędziom do inspekcji kodu, takim jak lint, aby wykrywać te bardziej subtelne problemy z kodem. Adnotacje są dodawane jako tagi metadanych, które możesz dołączać do zmiennych, parametrów i wartości zwracanych, aby sprawdzać wartości zwracane przez metody, przekazywane parametry, zmienne lokalne i pola. W połączeniu z narzędziami do sprawdzania kodu adnotacje mogą pomóc w wykrywaniu problemów, takich jak wyjątki od wskaźników null czy konflikty typów zasobów.

Android obsługuje różne adnotacje z biblioteki adnotacji w Jetpack. Dostęp do biblioteki możesz uzyskać za pomocą pakietu androidx.annotation.

Uwaga: jeśli moduł jest zależny od procesora adnotacji, musisz użyć konfiguracji zależności kapt lub ksp w przypadku Kotlina albo konfiguracji zależności annotationProcessor w przypadku Javy, aby dodać tę zależność.

Dodawanie adnotacji do projektu

Aby włączyć adnotacje w projekcie, dodaj zależność androidx.annotation:annotation do biblioteki lub aplikacji. Dodane adnotacje są sprawdzane podczas inspekcji kodu lub zadania lint.

Dodaj zależność biblioteki Jetpack Adnotacje

Biblioteka Jetpack Annotations jest publikowana w repozytorium Maven Google. Aby dodać do projektu bibliotekę Jetpack Anotations, dodaj ten wiersz do bloku dependencies w pliku build.gradle lub build.gradle.kts:

Kotlin

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

Groovy

dependencies {
    implementation 'androidx.annotation:annotation:1.9.1'
}
Następnie na pasku narzędzi lub w pojawiającym się powiadomieniu o synchronizacji kliknij Synchronizuj teraz.

Jeśli w swoim własnym module biblioteki używasz adnotacji, są one uwzględniane w ramach artefaktu Android Archive (AAR) w formacie XML w pliku annotations.zip. Dodanie zależności androidx.annotation nie powoduje uzależnienia od kolejnych użytkowników Twojej biblioteki.

Uwaga: jeśli używasz innych bibliotek Jetpacka, możesz nie musieć dodawać zależności androidx.annotation. Wiele innych bibliotek Jetpacka bazuje na bibliotece adnotacji, więc możesz już mieć do nich dostęp.

Pełną listę adnotacji znajdujących się w repozytorium Jetpack znajdziesz w dokumentacji biblioteki adnotacji Jetpack. Możesz też skorzystać z funkcji autouzupełniania, aby wyświetlić opcje dostępne dla instrukcji import androidx.annotation..

Przeprowadzanie inspekcji kodu

Aby rozpocząć sprawdzanie kodu w Android Studio, które obejmuje sprawdzanie poprawności adnotacji i automatyczne sprawdzanie błędów, w menu kliknij Analizuj > Sprawdzanie kodu. Android Studio wyświetla komunikaty o konflikcie, aby sygnalizować potencjalne problemy, w których Twój kod jest niezgodny z adnotacjami, oraz sugerować możliwe rozwiązania.

Możesz też wymusić adnotacje, uruchamiając zadanie lint za pomocą wiersza poleceń. Chociaż może to być przydatne do oznaczania problemów z serwerem ciągłej integracji, zadanie lint nie wymusza adnotacji nullości (opisanych w następnej sekcji); robi to tylko Android Studio. Więcej informacji o włączaniu i uruchamianiu kontroli lint znajdziesz w artykule Ulepszanie kodu za pomocą kontroli lint.

Konflikty adnotacji generują ostrzeżenia, ale nie uniemożliwiają kompilacji aplikacji.

Adnotacje dotyczące wartości NULL

W kodzie Java adnotacje nullości mogą być przydatne do wymuszania, czy wartości mogą być null. W kodzie Kotlina są one mniej przydatne, ponieważ Kotlin ma wbudowane reguły dotyczące możliwości wystąpienia wartości null, które są egzekwowane w czasie kompilacji.

Dodaj adnotacje @Nullable@NonNull, aby sprawdzić, czy dana zmienna, parametr lub wartość zwracana jest pusta. Adnotacja @Nullable wskazuje zmienną, parametr lub wartość zwracaną, która może być pusta. @NonNull wskazuje zmienną, parametr lub wartość zwracaną, która nie może być pusta.

Jeśli na przykład zmienna lokalna zawierająca wartość null jest przekazywana jako parametr do metody z dołączoną adnotacją @NonNull, kompilacja kodu powoduje ostrzeżenie o konflikcie z wartością inną niż null. Próba odwołania się do wyniku metody oznaczonej symbolem @Nullable bez wcześniejszego sprawdzenia, czy wynik jest pusty, powoduje ostrzeżenie o wartości null. Używaj funkcji @Nullable do wartości zwracanej przez metodę tylko wtedy, gdy każde użycie metody musi być wyraźnie sprawdzane pod kątem wartości null.

Poniższy przykład pokazuje, jak w praktyce działa dopuszczanie wartości null. Przykładowy kod Kotlina nie korzysta z adnotacji @NonNull, ponieważ jest ona automatycznie dodawana do wygenerowanego kodu bajtowego, gdy określony jest typ, który nie może być pusty. Przykład w języku Java korzysta z adnotacji @NonNull w przypadku parametrów contextattrs, aby sprawdzić, czy przekazane wartości parametrów nie są puste. Sprawdza też, czy metoda onCreateView() nie zwraca wartości 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) {
      ...
      }
...

Analiza wartości null

Android Studio obsługuje przeprowadzanie analizy wartości null w celu automatycznego wnioskowania i wstawiania do kodu adnotacji o braku wartości null. Analiza dopuszczalności wartości null skanuje kontrakty za pomocą hierarchii metod w kodzie, aby wykryć:

  • Metody wywołań, które mogą zwracać wartość null.
  • Metody, które nie powinny zwracać wartości null.
  • Zmienne, takie jak pola, zmienne lokalne i parametry, które mogą mieć wartość null.
  • Zmienne, takie jak pola, zmienne lokalne i parametry, które nie mogą zawierać wartości null.

Następnie analiza automatycznie wstawia odpowiednie adnotacje null w wykrytych lokalizacjach.

Aby w Android Studio przeprowadzić analizę wartości null, wybierz Analizuj > Wnioskuj o wartości null. Android Studio wstawia adnotacje Androida @Nullable@NonNull w wykrytych lokalizacjach w Twoim kodzie. Po przeprowadzeniu analizy pustych wartości warto zweryfikować wstrzyknięte adnotacje.

Uwaga: podczas dodawania adnotacji nullości autouzupełnianie może sugerować adnotacje IntelliJ @Nullable i @NotNull zamiast adnotacji nullości na Androida. Może też automatycznie zaimportować odpowiednią bibliotekę. Sprawdzacz lint w Android Studio sprawdza jednak tylko adnotacje null na Androida. Podczas sprawdzania adnotacji sprawdź, czy Twój projekt używa adnotacji null na Androida, aby sprawdzacz lint mógł odpowiednio poinformować Cię o błędach podczas inspekcji kodu.

Adnotacje zasobów

Walidowanie typów zasobów może być przydatne, ponieważ odwołania do zasobów w Androidzie, takich jak zasoby drawablestring, są przekazywane jako liczby całkowite.

Kod, który oczekuje, że parametr odwołuje się do określonego typu zasobu, np. String, może zostać przekazany do oczekiwanego typu odwołania int, ale tak naprawdę odwołuje się do innego typu zasobu, np. zasobu R.string.

Na przykład dodaj adnotacje @StringRes, aby sprawdzić, czy parametr zasobu zawiera odwołanie R.string, jak pokazano tutaj:

Kotlin

abstract fun setTitle(@StringRes resId: Int)

Java

public abstract void setTitle(@StringRes int resId)

Podczas sprawdzania kodu adnotacja generuje ostrzeżenie, jeśli w parametrze nie jest przekazywane odwołanie R.string.

Adnotacje do innych typów zasobów, takich jak @DrawableRes, @DimenRes, @ColorRes i @InterpolatorRes, można dodawać za pomocą tego samego formatu i uruchamiać je podczas inspekcji kodu.

Jeśli Twój parametr obsługuje wiele typów zasobów, możesz umieścić w nim więcej niż 1 adnotację typu zasobu. Użyj @AnyRes, aby wskazać, że adnotowany parametr może być dowolnym typem zasobu R.

Chociaż możesz użyć atrybutu @ColorRes, aby określić, że parametr powinien być zasobem koloru, liczba całkowita koloru (w formacie RRGGBB lub AARRGGBB) nie jest rozpoznawana jako zasób koloru. Zamiast tego użyj adnotacji @ColorInt, aby wskazać, że parametr musi być liczbą całkowitą koloru. Narzędzia do kompilacji będą oznaczać nieprawidłowy kod, który przekazuje do metody opatrzonej adnotacjami identyfikator zasobu koloru, np. android.R.color.black, zamiast koloru w postaci liczby całkowitej.

Adnotacje wątków

Adnotacje wątku sprawdzają, czy metoda jest wywoływana z określonego typu wątku. Obsługiwane są te adnotacje wątku:

Narzędzia do tworzenia traktują adnotacje @MainThread i @UiThread jako wymienne, więc możesz wywoływać metody @UiThread z metod @MainThread i odwrotnie. W przypadku aplikacji systemowych z wieloma widokami w różnych wątkach może się jednak zdarzyć, że wątek interfejsu użytkownika będzie inny niż główny wątek. Dlatego metody powiązane z hierarchią widoku aplikacji należy opatrzyć adnotacją @UiThread, a metody powiązane z cyklem życia aplikacji – adnotacją @MainThread.

Jeśli wszystkie metody w klasie mają te same wymagania dotyczące wątków, możesz dodać do klasy pojedynczą adnotację wątku, aby sprawdzić, czy wszystkie metody w klasie są wywoływane z tego samego typu wątku.

Typowym zastosowaniem adnotacji w wątku jest sprawdzenie, czy metody lub klasy oznaczone adnotacjami @WorkerThread są wywoływane tylko z odpowiedniego wątku w tle.

Adnotacje ograniczeń wartości

Aby sprawdzać wartości parametrów przekazywanych, użyj adnotacji @IntRange, @FloatRange@Size. Zarówno @IntRange, jak i @FloatRange są najbardziej przydatne w przypadku parametrów, w których przypadku użytkownicy mogą podać nieprawidłowy zakres.

Adnotacja @IntRange sprawdza, czy wartość parametru typu integer lub long mieści się w określonym zakresie. W tym przykładzie parametr alpha musi zawierać liczbę całkowitą od 0 do 255:

Kotlin

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

Java

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

Adnotacja @FloatRange sprawdza, czy wartość parametru typu float lub double mieści się w określonym zakresie wartości zmiennoprzecinkowych. Ten przykład wskazuje, że parametr alpha musi zawierać wartość zmiennoprzecinkową od 0,0 do 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) {...}

Adnotacja @Size sprawdza rozmiar kolekcji lub tablicy albo długość ciągu znaków. Adnotacji @Size można używać do weryfikowania tych jakości:

  • Minimalny rozmiar, np. @Size(min=2)
  • Maksymalny rozmiar, np. @Size(max=2)
  • Dokładny rozmiar, np. @Size(2)
  • Liczba, której wielokrotnością musi być rozmiar, np. @Size(multiple=2)

Na przykład @Size(min=1)sprawdza, czy kolekcja nie jest pusta, a @Size(3)sprawdza, czy tablica zawiera dokładnie 3 wartości.

Z przykładu poniżej wynika, że tablica location musi zawierać co najmniej 1 element:

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

adnotacje dotyczące uprawnień;

Użyj adnotacji @RequiresPermission, aby zweryfikować uprawnienia wywołującego metodę. Aby sprawdzić, czy na liście prawidłowych uprawnień znajduje się określone uprawnienie, użyj atrybutu anyOf. Aby sprawdzić zestaw uprawnień, użyj atrybutu allOf. W tym przykładzie metoda setWallpaper() jest opatrzona adnotacją, która wskazuje, że wywołujący tę metodę musi mieć uprawnienie 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;

Ten przykład wymaga, aby element wywołujący metodę copyImageFile() miał dostęp zarówno do odczytu do pamięci zewnętrznej, jak i do odczytu metadanych lokalizacji w kopiowanym obrazie:

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

W przypadku uprawnień do intencji umieść wymagane uprawnienia w polu ciągu, które określa nazwę działania intencji:

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

W przypadku uprawnień dostawców treści, które wymagają oddzielnych uprawnień do odczytu i zapisu, owiń każde z nich w annotację @RequiresPermission.Read lub @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");

Uprawnienia pośrednie

Jeśli uprawnienia zależą od konkretnej wartości podanej w parametrze metody, użyj @RequiresPermission na samym parametrze, nie wymieniając konkretnych uprawnień. Na przykład metoda startActivity(Intent) korzysta z pośredniego uprawnienia do intencji przekazywanej do metody:

Kotlin

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

Java

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

Gdy używasz uprawnień pośrednich, narzędzia do kompilacji przeprowadzają analizę przepływu danych, aby sprawdzić, czy argument przekazany do metody zawiera adnotacje @RequiresPermission. Następnie wymusza wszelkie istniejące adnotacje z parametru w samej metodzie. W przykładzie startActivity(Intent) adnotacje klasy Intent powodują wyświetlenie ostrzeżeń o nieprawidłowym użyciu startActivity(Intent), gdy do metody zostanie przekazana intencja bez odpowiednich uprawnień, jak widać na rysunku 1.

Rysunek 1. Ostrzeżenie wygenerowane z bezpośredniej adnotacji uprawnień w metodie startActivity(Intent).

Narzędzia do kompilacji generują ostrzeżenie w startActivity(Intent) na podstawie adnotacji dotyczącej nazwy działania w intencji w klasie 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";

W razie potrzeby możesz zastąpić @RequiresPermission wartością @RequiresPermission.Read lub @RequiresPermission.Write podczas dodawania adnotacji do parametru metody. Jednak w przypadku uprawnień pośrednich elementu @RequiresPermission nie należy używać w połączeniu z adnotacjami uprawnień do odczytu ani zapisu.

Adnotacje wartości zwracanych

Użyj adnotacji @CheckResult, aby sprawdzić, czy wynik metody lub zwracana wartość są rzeczywiście używane. Zamiast oznaczać @CheckResult każdą metodę niepustą, dodaj adnotację, aby wyjaśnić wyniki potencjalnie mylących metod.

Na przykład nowi programiści Java często błędnie sądzą, że <String>.trim() usuwa odstępy z oryginalnego ciągu. Adnotacje do metody z flagami @CheckResult oznaczają użycie <String>.trim(), gdy element wywołujący nie wykona żadnych działań związanych z zwracaną przez nią wartością.

Ten przykład opisuje metodę checkPermissions(), która pozwala sprawdzić, czy zwracana jest wartość zwracana metody. Zawiera też nazwę metody enforcePermission(), która zostanie zaproponowana deweloperowi jako zamiennik:

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

Adnotacje CallSuper

Użyj adnotacji @CallSuper, aby sprawdzić, czy metoda zastępowania wywołuje superimplementację.

W tym przykładzie metoda onCreate() jest opatrzona adnotacjami, aby zapewnić, że wszystkie implementacje metody zastępczej wywołują metodę super.onCreate():

Kotlin

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

Java

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

Adnotacje typu

Adnotacje Typedef określają, czy określony parametr, zwracana wartość lub pole odwołuje się do konkretnego zestawu stałych. Umożliwiają też automatyczne uzupełnianie kodu, aby automatycznie oferować dozwolone stałe.

Użyj adnotacji @IntDef i @StringDef, aby utworzyć adnotacje z wyliczeniami zbiorów liczb całkowitych i ciągów znaków, które służą do sprawdzania innych typów odwołań do kodu.

Adnotacje typu „Typedef” używają instrukcji @interface do deklarowania nowego typu adnotacji z wyliczeniem. Adnotacje @IntDef i @StringDef wraz z adnotacją @Retention adnotują nową adnotację i są niezbędne do zdefiniowania typu wyliczeniowego. Adnotacja @Retention(RetentionPolicy.SOURCE) informuje kompilator, aby nie przechowywać danych adnotacji za pomocą enumeracji w pliku .class.

W tym przykładzie pokazano, jak utworzyć adnotację, która sprawdza, czy wartość przekazana jako parametr metody odwołuje się do jednej z zdefiniowanych stałych:

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

Podczas kompilowania tego kodu generowane jest ostrzeżenie, jeśli parametr mode nie odwołuje się do jednej z zdefiniowanych stałych (NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST lub NAVIGATION_MODE_TABS).

Połącz @IntDef@IntRange, aby wskazać, że liczba całkowita może być określonym zbiorem stałych lub wartością w zakresie.

Włącz łączenie stałych z flagami

Jeśli użytkownicy mogą łączyć dozwolone stałe z flagą (np. |, &, ^ itd.), możesz zdefiniować adnotację za pomocą atrybutu flag, aby sprawdzić, czy parametr lub wartość zwracana odwołuje się do prawidłowego wzorca.

Ten przykład tworzy adnotację DisplayOptions z listą prawidłowych stałych DISPLAY_:

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

...

Gdy kompilujesz kod z flagą adnotacji, generowane jest ostrzeżenie, jeśli ozdobiony parametr lub wartość zwracana nie odwołuje się do prawidłowego wzorca.

Zachowaj adnotację

Adnotacja @Keepzapewnia, że adnotowana klasa lub metoda nie zostanie usunięta, gdy kod zostanie zminiaturyzowany w czasie kompilacji. Ta adnotacja jest zwykle dodawana do metod i klas, do których dostęp uzyskuje się za pomocą odbicia lustrzanego, aby zapobiec traktowaniu kodu przez kompilator jako nieużywanego.

Uwaga: klasy i metody, które dodajesz za pomocą adnotacji @Keep, zawsze pojawiają się w pliku APK aplikacji, nawet jeśli nigdy nie odwołujesz się do tych klas i metod w jej logice.

Aby zmniejszyć rozmiar aplikacji, zastanów się, czy w aplikacji jest konieczne zachowanie każdej adnotacji @Keep. Jeśli używasz odbicia lustrzanego, aby uzyskać dostęp do adnotowanej klasy lub metody, użyj w regułach ProGuard instrukcji warunkowej -if, określając klasę, która wykonuje wywołania odbicia lustrzanego.

Więcej informacji o minifikacji kodu i określaniu, którego kodu nie należy usuwać, znajdziesz w artykule Zmniejsz, zaciemnij i zoptymalizuj aplikację.

Adnotacje dotyczące widoczności kodu

Użyj poniższych adnotacji, aby wskazać widoczność określonych części kodu, takich jak metody, klasy, pola czy pakiety.

Udostępnianie kodu na potrzeby testowania

Adnotacja @VisibleForTesting wskazuje, że adnotowana metoda jest bardziej widoczna niż zwykle, co ułatwia jej testowanie. Ta adnotacja ma opcjonalny argument otherwise, który pozwala określić, jak widoczna miałaby być metoda, gdyby nie potrzeba wyświetlania jej na potrzeby testowania. Lint używa argumentu otherwise, aby narzucić wymaganą widoczność.

W tym przykładzie wartość myMethod() to zwykle private, ale w przypadku testów jest to package-private. Po oznaczeniu VisibleForTesting.PRIVATE lint wyświetla komunikat, gdy ta metoda jest wywoływana spoza kontekstu, do którego zezwala dostęp private, na przykład z innej jednostki kompilacji.

Kotlin

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

Java

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

Możesz też podać @VisibleForTesting(otherwise = VisibleForTesting.NONE), aby wskazać, że metoda istnieje tylko do testowania. Ten formularz jest taki sam jak przy użyciu @RestrictTo(TESTS). Oba wykonują te same kontrole.

Ograniczanie interfejsu API

Adnotacja @RestrictTo wskazuje, że dostęp do oznaczonego interfejsu API (pakietu, klasy lub metody) jest ograniczony w następujący sposób:

Podklasy

Aby ograniczyć dostęp do interfejsu API tylko do podklas, użyj formularza adnotacji @RestrictTo(RestrictTo.Scope.SUBCLASSES).

Dostęp do tego interfejsu API mają tylko klasy, które rozszerzają tę z adnotacjami. Modyfikator Java protected nie jest wystarczająco restrykcyjny, ponieważ zezwala na dostęp z niepowiązanych klas w tym samym pakiecie. Zdarzają się też sytuacje, w których chcesz zostawić metodę public dla elastyczności w przyszłości, ponieważ nigdy nie można utworzyć metody protected ani zastąpionej wcześniej public, ale chcesz dać wskazówkę, że klasa jest przeznaczona do użycia w ramach klasy lub tylko do podklas.

Biblioteki

Użyj formularza adnotacji @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX), aby ograniczyć dostęp przez interfejs API tylko do swoich bibliotek.

Dostęp do interfejsu API z adnotacjami ma tylko kod Twojej biblioteki. Dzięki temu możesz nie tylko porządkować kod w dowolnej hierarchii pakietu, ale też udostępniać go grupie powiązanych bibliotek. Ta opcja jest już dostępna w przypadku bibliotek Jetpacka, które zawierają dużo kodu implementacji, który nie jest przeznaczony do użytku zewnętrznego, ale musi być public, aby udostępnić go w różnych uzupełniających bibliotekach Jetpacka.

Testowanie

Aby uniemożliwić innym programistom dostęp do interfejsów API do testowania, użyj formularza adnotacji @RestrictTo(RestrictTo.Scope.TESTS).

Do interfejsu API z adnotacjami dostęp ma tylko kod testowy. Zapobiega to używaniu przez innych programistów interfejsów API do celów programistycznych, które mają służyć tylko do testowania.