Ulepsz inspekcję kodu za pomocą adnotacji

Narzędzia do inspekcji kodu, takie jak Linter, mogą pomóc Ci w znalezieniu problemów i ulepszaniu kodu, ale narzędzia do inspekcji są w stanie wykryć tylko wiele. Identyfikatory zasobów Androidint W takiej sytuacji aplikacja może się nieprawidłowo renderować lub w ogóle nie uruchomić, nawet jeśli przeprowadzisz kontrolę kodu.

Adnotacje umożliwiają przekazywanie wskazówek narzędziom do inspekcji kodu (np. lint), które ułatwiają wykrywanie bardziej subtelnych problemów z kodem. Adnotacje są dodawane jako tagi metadanych, które dołączane do zmiennych, parametrów i zwracanych wartości służą do sprawdzania zwracanych wartości, przekazywanych parametrów, zmiennych lokalnych i pól. 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ć w pakiecie androidx.annotation.

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

Dodawanie adnotacji do projektu

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

Dodaj zależność biblioteki Jetpack Adnotacje

Biblioteka Jetpack Adnotacje została opublikowana w repozytorium Google Maven. Aby dodać do projektu bibliotekę Adnotacji Jetpack do projektu, umieść ten wiersz w bloku dependencies w pliku build.gradle lub build.gradle.kts:

Kotlin

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

Odlotowe

dependencies {
    implementation 'androidx.annotation:annotation:1.8.0'
}
Następnie na pasku narzędzi lub w powiadomieniu o synchronizacji, które się pojawią, kliknij Synchronizuj teraz.

Jeśli używasz adnotacji w swoim module biblioteki, adnotacje zostaną dołączone jako część artefaktu archiwum Androida (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 Jetpack, dodanie zależności androidx.annotation może nie być konieczne. 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 uruchomić kontrolę kodu w Android Studio, która obejmuje weryfikowanie adnotacji i automatyczne sprawdzanie lint, w menu wybierz Analizuj > Zbadaj kod. Android Studio wyświetla komunikaty o konfliktach, aby sygnalizować potencjalne problemy, w przypadku których występuje konflikt kodu z adnotacjami, i podpowiadać możliwe rozwiązania.

Możesz też wymusić stosowanie adnotacji, uruchamiając zadanie lint za pomocą wiersza poleceń. Chociaż może to być przydatne przy oznaczaniu problemów z serwerem ciągłej integracji, zadanie lint nie wymusza adnotacji o wartości null (opisanej w sekcji poniżej) – robi to tylko Android Studio. Więcej informacji o włączaniu i przeprowadzaniu kontroli lint znajdziesz w artykule o ulepszaniu kodu za pomocą kontroli lintowania.

Chociaż konflikty adnotacji generują ostrzeżenia, nie uniemożliwiają one skompilowania aplikacji.

Adnotacje o wartości null

Adnotacje null mogą być przydatne w kodzie Java, gdy trzeba ustalić, czy wartości mogą mieć wartość null. Są one mniej przydatne w kodzie Kotlin, ponieważ Kotlin ma wbudowane reguły dopuszczania wartości null, które są egzekwowane w czasie kompilacji.

Dodaj adnotacje @Nullable i @NonNull, by sprawdzić wartość null danej zmiennej, parametru lub zwróconej wartości. Adnotacja @Nullable wskazuje zmienną, parametr lub wartość zwracaną, która może mieć wartość null. @NonNull oznacza zmienną, parametr lub wartość zwracaną, które nie mogą być puste.

Jeśli na przykład zmienna lokalna zawierająca wartość null jest przekazywana jako parametr do metody z adnotacją @NonNull dołączoną do tego parametru, utworzenie kodu generuje ostrzeżenie wskazujące konflikt niepusty. Dodatkowo próba odwoływania się do wyniku metody oznaczonej przez @Nullable bez wcześniejszego sprawdzenia, czy wynik ma wartość null, powoduje też wyświetlenie ostrzeżenia o braku wartości. Używaj @Nullable do wartości zwracanej przez metodę tylko wtedy, gdy każde jej użycie musi być wyraźnie zaznaczone.

Poniższy przykład pokazuje, jak w praktyce działa dopuszczanie wartości null. Przykładowy kod Kotlin nie wykorzystuje adnotacji @NonNull, ponieważ jest ona automatycznie dodawana do wygenerowanego kodu bajtowego po określeniu typu niedopuszczającego wartości null. Przykład w Javie wykorzystuje adnotację @NonNull w parametrach context i attrs, aby sprawdzić, czy przekazywane wartości parametrów nie mają wartości null. Sprawdza też, czy sama 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 o wartości null w wykrytych lokalizacjach.

Aby w Android Studio przeprowadzić analizę wartości null, wybierz Analizuj > Wnioskuj o wartości null. Android Studio wstawia adnotacje @Nullable i @NonNull w wykrytych miejscach w kodzie. Po przeprowadzeniu analizy o wartości null warto sprawdzić wstawione adnotacje.

Uwaga: gdy dodajesz adnotacje o stanie null, autouzupełnianie może sugerować adnotacje IntelliJ @Nullable i @NotNull zamiast zerowych adnotacji Androida i może automatycznie zaimportować odpowiednią bibliotekę. Narzędzie do sprawdzania lintowania w Android Studio szuka jednak tylko adnotacji o wartości null w Androidzie. Weryfikując adnotacje, sprawdź, czy Twój projekt używa pustych adnotacji Androida. Dzięki temu narzędzie do sprawdzania lint będzie mogło odpowiednio powiadomić Cię podczas inspekcji kodu.

Adnotacje dotyczące zasobów

Weryfikowanie typów zasobów może być przydatne, ponieważ odwołania Androida do zasobów, takich jak zasoby drawable i string, są przekazywane jako liczby całkowite.

Kod, który oczekuje, że parametr będzie odwoływać się do określonego typu zasobu, takiego jak String, można przekazać do oczekiwanego typu odwołania int, ale w rzeczywistości odwołuje się do innego typu zasobu, na przykład do zasobu R.string.

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

Kotlin

abstract fun setTitle(@StringRes resId: Int)

Java

public abstract void setTitle(@StringRes int resId)

Podczas inspekcji kodu adnotacja generuje ostrzeżenie, jeśli w parametrze nie zostanie przekazane odwołanie do funkcji 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 parametr z adnotacjami może być dowolnym typem zasobu R.

Za pomocą @ColorRes możesz określić, że parametr powinien być zasobem koloru, jednak 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ą określającą kolor. Narzędzia do kompilacji oznaczą nieprawidłowy kod, który przekazuje do metod z adnotacjami nieprawidłowy kod, który przekazuje identyfikator zasobu koloru, np. android.R.color.black, zamiast liczby całkowitej koloru.

Adnotacje w wątkach

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 kompilacji 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 różnych wątków może się jednak różnić od wątku głównego. Dlatego musisz dodawać adnotacje do metod powiązanych z hierarchią widoku aplikacji za pomocą parametru @UiThread, a za pomocą właściwości @MainThread tylko do metod powiązanych z cyklem życia aplikacji.

Jeśli wszystkie metody w klasie mają takie same wymagania dotyczące wątków, możesz dodać do klasy adnotację z pojedynczym wątkiem, 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 z adnotacjami @WorkerThread są wywoływane tylko z odpowiedniego wątku w tle.

Adnotacje ograniczenia wartości

Używaj adnotacji @IntRange, @FloatRange i @Size, aby sprawdzać wartości przekazywanych parametrów. Zarówno @IntRange, jak i @FloatRange są najbardziej przydatne w przypadku parametrów, w których użytkownicy mogą pomylić zakres.

Adnotacja @IntRange sprawdza, czy liczba całkowita lub długa wartość parametru 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 zmiennoprzecinkowego lub podwójnej precyzji 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. 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 rozmiar musi być wielokrotnością wartości, np. @Size(multiple=2)

Na przykład funkcja @Size(min=1) sprawdza, czy kolekcja nie jest pusta, a pole @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ń

Aby zweryfikować uprawnienia wywołującego metodę, użyj adnotacji @RequiresPermission. Aby sprawdzić pojedyncze uprawnienie na liście prawidłowych uprawnień, użyj atrybutu anyOf. Aby sprawdzić zestaw uprawnień, użyj atrybutu allOf. W tym przykładzie opisano metodę setWallpaper() wskazującą, że element wywołujący metody 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órzy potrzebują osobnych uprawnień do odczytu i zapisu, umieść wszystkie wymagane uprawnienia w adnotacji @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 uprawnienie zależy od konkretnej wartości podanej w parametrze metody, użyj w nim właściwości @RequiresPermission bez podawania 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 korzystasz z 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 przez adnotację uprawnień pośrednich w metodzie startActivity(Intent).

Narzędzia do kompilacji generują ostrzeżenie startActivity(Intent) na podstawie adnotacji dotyczącej odpowiedniej nazwy działania 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 lub wartość zwracana metody faktycznie są używane. Zamiast dodawać adnotacje do wszystkich niepustych metod za pomocą właściwości @CheckResult, dodaj je, aby objaśniać wyniki potencjalnie wprowadzających w błąd 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. Metoda enforcePermission() jest też nazwana jako metoda sugerowana 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ę.

Ten przykład adnotuje metodę onCreate(), aby zapewnić, że implementacje zastępujące wywołują metodę super.onCreate():

Kotlin

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

Java

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

Adnotacje Typedef

Adnotacje Typedef określają, czy określony parametr, zwracana wartość lub pole odwołuje się do konkretnego zestawu stałych. Umożliwiają też uzupełnianie kodu i automatyczne proponowanie dozwolonych stałych wartości.

Za pomocą adnotacji @IntDef i @StringDef możesz tworzyć wyliczane adnotacje w postaci liczb całkowitych i zbiorów ciągów znaków do sprawdzania innych typów odwołań do kodu.

Adnotacje Typedef korzystają z pola @interface do deklarowania nowego wyliczanego typu adnotacji. Adnotacje @IntDef i @StringDef wraz z adnotacją @Retention opisują nową adnotację i są niezbędne do zdefiniowania określonego typu. Adnotacja @Retention(RetentionPolicy.SOURCE) informuje kompilator, aby nie zapisywał wyliczonych danych adnotacji w pliku .class.

Poniższy przykład pokazuje, jak utworzyć adnotację, która sprawdza, czy wartość przekazywana jako parametr metody odwołuje się do jednej ze 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);
}

Gdy utworzysz ten kod, zostanie wygenerowane ostrzeżenie, jeśli parametr mode nie będzie odwoływać się do jednej ze zdefiniowanych stałych (NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST lub NAVIGATION_MODE_TABS).

Połącz wartości @IntDef i @IntRange, by wskazać, że liczba całkowita może być określonym zbiorem stałych lub wartości z danego zakresu.

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

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

W tym przykładzie tworzy się 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 {}

...

W przypadku tworzenia kodu przy użyciu flagi adnotacji, jeśli parametr dekoracyjny lub zwracana wartość nie odnosi się do prawidłowego wzorca, generowane jest ostrzeżenie.

Zachowaj adnotację

Adnotacja @Keep gwarantuje, że klasa lub metoda z adnotacjami nie zostaną usunięte, gdy kod zostanie zminimalizowany w czasie kompilacji. Ta adnotacja jest zwykle dodawana do metod i klas, do których dostęp jest uzyskiwany za pomocą refleksji, aby kompilator nie traktował kodu 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 ograniczyć rozmiar aplikacji, zastanów się, czy konieczne jest zachowanie w niej każdej adnotacji @Keep. Jeśli korzystasz z odbicia, by uzyskać dostęp do klasy lub metody z adnotacjami, użyj w regułach ProGuard warunkowego -if, określając klasę, która wywołuje odbiór.

Więcej informacji o zmniejszaniu kodu i określaniu, który z nich nie ma być usuwany, znajdziesz w artykule Zmniejszanie, zaciemnianie i optymalizowanie aplikacji.

Adnotacje widoczności kodu

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

Udostępnij kod do testowania

Adnotacja @VisibleForTesting wskazuje, że metoda z adnotacjami jest bardziej widoczna niż zwykle, aby umożliwić jej testowanie. Ta adnotacja ma opcjonalny argument otherwise, który pozwala określić widoczność metody w sytuacji, gdy nie ma być widoczna na potrzeby testów. Lint używa argumentu otherwise do egzekwowania zamierzonej widoczności.

W poniższym przykładzie myMethod() to zwykle private, ale w testach jest 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ć właściwość @VisibleForTesting(otherwise = VisibleForTesting.NONE), aby wskazać, że metoda istnieje tylko na potrzeby testów. Ten formularz jest taki sam jak przy użyciu @RestrictTo(TESTS). Oba wykonują te same czynności lintowania.

Ograniczanie interfejsu API

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

Podklasy

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

Dostęp do tego interfejsu API mają tylko klasy, które rozszerzają tę z adnotacją. Modyfikator protected w Javie nie jest wystarczająco restrykcyjny, ponieważ umożliwia 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. Pozwala to nie tylko uporządkować kod w dowolnej hierarchii pakietów, ale także współużytkować go między grupą powiązanych bibliotek. Ta opcja jest już dostępna w bibliotekach Jetpack, które mają dużo kodu implementacji nieprzeznaczonego do użytku zewnętrznego. Aby jednak móc ją udostępniać w różnych uzupełniających bibliotekach Jetpack, musi to być public.

Testowanie

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

Dostęp do interfejsu API z adnotacjami ma tylko kod testowy. Dzięki temu inni deweloperzy nie mogą używać interfejsów API do programowania, które mają służyć tylko do testowania.