Narzędzia do sprawdzania kodu, takie jak lint, mogą pomóc w znajdowaniu problemów i ulepszaniu kodu, ale ich możliwości są ograniczone. Na przykład identyfikatory zasobów Androida używają typu int do identyfikowania ciągów znaków, grafiki, kolorów i innych typów zasobów, więc narzędzia do sprawdzania nie mogą określić, kiedy określono zasób tekstowy, gdy powinien być określony kolor. Oznacza to, że aplikacja może renderować się nieprawidłowo lub w ogóle się nie uruchamiać, nawet jeśli używasz kontroli kodu.
Adnotacje umożliwiają przekazywanie wskazówek narzędziom do sprawdzania kodu, takim jak lint, aby ułatwić wykrywanie tych bardziej subtelnych problemów z kodem. Adnotacje są dodawane jako tagi metadanych, które dołączasz 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 wskaźnika o wartości null i konflikty typów zasobów.
Android obsługuje różne adnotacje za pomocą biblioteki adnotacji 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 języka Kotlin albo konfiguracji zależności annotationProcessor w przypadku języka Java, 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. Wszystkie dodane adnotacje są sprawdzane podczas kontroli kodu lub zadania lint.
Dodawanie zależności biblioteki adnotacji Jetpack
Biblioteka adnotacji Jetpack jest opublikowana w repozytorium Maven Google.
Aby dodać do projektu bibliotekę Jetpack Annotations, dodaj ten wiersz w bloku dependencies pliku build.gradle lub build.gradle.kts:
Kotlin
dependencies { implementation("androidx.annotation:annotation:1.11.0") }
Dynamiczny
dependencies { implementation 'androidx.annotation:annotation:1.11.0' }
Jeśli używasz adnotacji we własnym module biblioteki, są one dołączane jako część artefaktu Android Archive (AAR) w formacie XML w pliku annotations.zip. Dodanie zależności androidx.annotation nie powoduje dodania zależności dla 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 zależy od biblioteki adnotacji, więc możesz już mieć dostęp do adnotacji.
Pełną listę adnotacji zawartych w repozytorium Jetpack znajdziesz w dokumentacji biblioteki adnotacji Jetpack. Możesz też użyć funkcji autouzupełniania, aby wyświetlić dostępne opcje instrukcji import androidx.annotation..
Przeprowadzanie kontroli kodu
Aby rozpocząć sprawdzanie kodu w Android Studio, które obejmuje weryfikację adnotacji i automatyczne sprawdzanie błędów, w menu wybierz Analyze (Analizuj) > Inspect Code (Sprawdź kod). Android Studio wyświetla komunikaty o konfliktach, aby sygnalizować potencjalne problemy, w których kod jest sprzeczny z adnotacjami, i sugerować możliwe rozwiązania.
Możesz też wymusić adnotacje, uruchamiając zadanie lint za pomocą wiersza poleceń. Może to być przydatne do oznaczania problemów z serwerem trybu ciągłej integracji, ale zadanie lint nie wymusza adnotacji o wartości null (opisanych w następnej sekcji) – robi to tylko Android Studio. Więcej informacji o włączaniu i przeprowadzaniu kontroli lint znajdziesz w artykule Ulepszanie kodu za pomocą kontroli lint.
Chociaż konflikty adnotacji generują ostrzeżenia, nie uniemożliwiają one kompilacji aplikacji.
Adnotacje dotyczące wartości null
Adnotacje dotyczące wartości null mogą być przydatne w kodzie Javy, aby wymusić, czy wartości mogą być równe null. Są one mniej przydatne w kodzie Kotlin, ponieważ Kotlin ma wbudowane reguły dopuszczalności wartości null, które są egzekwowane w czasie kompilacji.Dodaj adnotacje @Nullable i @NonNull, aby sprawdzić, czy dana zmienna, parametr lub zwracana wartość nie są puste. Adnotacja @Nullable wskazuje zmienną, parametr lub wartość zwracaną, która może mieć wartość null.
@NonNull wskazuje zmienną, parametr lub zwracaną wartość, która nie może być pusta.
Jeśli na przykład zmienna lokalna zawierająca wartość null zostanie przekazana jako parametr do metody z adnotacją @NonNull dołączoną do tego parametru, podczas kompilowania kodu zostanie wygenerowane ostrzeżenie wskazujące na konflikt z wartością inną niż null. Próba odwołania się do wyniku metody oznaczonej adnotacją @Nullable bez uprzedniego sprawdzenia, czy wynik jest wartością null, spowoduje wygenerowanie ostrzeżenia o wartości null. Używaj adnotacji @Nullable w wartości zwracanej przez metodę tylko wtedy, gdy każde użycie metody musi być wyraźnie sprawdzone pod kątem wartości null.
Poniższy przykład pokazuje, jak działa dopuszczalność wartości null. Przykładowy kod w języku Kotlin nie wykorzystuje adnotacji @NonNull, ponieważ jest ona automatycznie dodawana do wygenerowanego kodu bajtowego, gdy określony jest typ, który nie może mieć wartości null. W przykładzie w języku Java użyto adnotacji @NonNull w parametrach context i attrs, aby sprawdzić, czy przekazane wartości parametrów nie są równe 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 dopuszczalności wartości null
Android Studio obsługuje analizę dopuszczalności wartości null, aby automatycznie wnioskować i wstawiać adnotacje o wartości null w kodzie. Analiza dopuszczalności wartości null skanuje kontrakty w hierarchiach metod w kodzie, aby wykryć:
- Wywoływanie metod, 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 przeprowadzić analizę dopuszczania wartości null w Android Studio, wybierz Analizuj > Wnioskuj o wartości null. Android Studio wstawia adnotacje Androida @Nullable i @NonNull w wykrytych lokalizacjach w kodzie. Po przeprowadzeniu analizy wartości null warto sprawdzić wstawione adnotacje.
Uwaga: podczas dodawania adnotacji o wartości null autouzupełnianie może sugerować adnotacje IntelliJ
@Nullable i @NotNull zamiast adnotacji o wartości null na Androidzie i może automatycznie importować odpowiednią bibliotekę. Jednak narzędzie do sprawdzania błędów w Android Studio szuka tylko adnotacji null na Androida. Podczas weryfikowania adnotacji upewnij się, że projekt używa adnotacji null na Androida, aby narzędzie do sprawdzania błędów mogło prawidłowo powiadamiać Cię podczas sprawdzania kodu.
Adnotacje zasobów
Sprawdzanie typów zasobów może być przydatne, ponieważ odwołania do zasobów na Androidzie, takie jak zasoby obiektów rysowalnych i zasobów tekstowych, są przekazywane jako liczby całkowite.
Kod, który oczekuje, że parametr będzie odwoływać się do określonego typu zasobu, np. String, może zostać przekazany do oczekiwanego typu odwołania int, ale w rzeczywistości odwoływać się do innego typu zasobu, np. R.string.
Możesz na przykład dodać 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 do R.string.
Adnotacje dotyczące innych typów zasobów, takich jak @DrawableRes, @DimenRes, @ColorRes i @InterpolatorRes, można dodawać przy użyciu tego samego formatu adnotacji i uruchamiać podczas sprawdzania kodu.
Jeśli parametr obsługuje wiele typów zasobów, możesz dodać do niego więcej niż 1 adnotację. Użyj @AnyRes, aby wskazać, że adnotowany parametr może być dowolnym typem zasobu R.
Chociaż możesz użyć @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 metod z adnotacjami identyfikator zasobu koloru, np. android.R.color.black, zamiast liczby całkowitej koloru.
Adnotacje do wątku
Adnotacje wątków sprawdzają, czy metoda jest wywoływana z określonego typu wątku. Obsługiwane są te adnotacje wątków:
Narzędzia do kompilacji traktują adnotacje @MainThread i @UiThread jako wymienne, więc możesz wywoływać metody @UiThread z metod @MainThread i odwrotnie. Jednak wątek interfejsu może się różnić od wątku głównego w przypadku aplikacji systemowych z wieloma widokami w różnych wątkach. Dlatego metody powiązane z hierarchią widoków aplikacji należy oznaczać 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ątków jest sprawdzanie, czy metody lub klasy oznaczone adnotacją @WorkerThread są wywoływane tylko z odpowiedniego wątku w tle.
Adnotacje dotyczące ograniczeń wartości
Użyj adnotacji @IntRange, @FloatRange i @Size, aby sprawdzić poprawność wartości przekazywanych parametrów. Zarówno @IntRange, jak i @FloatRange są najbardziej przydatne, gdy są stosowane do parametrów, w przypadku których 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ą z zakresu 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. Z poniższego przykładu wynika, że parametr alpha musi zawierać wartość zmiennoprzecinkową z zakresu 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 weryfikacji tych cech:
- 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.
Poniższy przykład wskazuje, ż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 sprawdzić uprawnienia elementu wywołującego metodę. Aby sprawdzić pojedyncze uprawnienie z listy prawidłowych uprawnień, użyj atrybutu anyOf. Aby sprawdzić zestaw uprawnień, użyj atrybutu allOf. W poniższym przykładzie metoda setWallpaper() jest oznaczona adnotacją wskazującą, że wywołujący 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;
W poniższym przykładzie wywołujący metodę copyImageFile() musi mieć dostęp do odczytu zarówno do pamięci zewnętrznej, jak i do metadanych lokalizacji w skopiowanym 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 definiuje 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ń do mechanizmów dostarczania treści, które wymagają osobnych uprawnień do odczytu i zapisu, umieść każde wymaganie dotyczące uprawnień 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 @RequiresPermission w samym parametrze bez podawania konkretnych uprawnień.
Na przykład metoda startActivity(Intent) używa uprawnienia pośredniego w intencji przekazanej 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 ma adnotacje @RequiresPermission. Następnie wymuszają wszelkie istniejące adnotacje z parametru w samej metodzie. W przykładzie startActivity(Intent) adnotacje w klasie Intent powodują wyświetlanie ostrzeżeń o nieprawidłowym użyciu startActivity(Intent), gdy do metody przekazywana jest intencja bez odpowiednich uprawnień, jak pokazano na rysunku 1.
Rysunek 1. Ostrzeżenie wygenerowane na podstawie adnotacji o uprawnieniach pośrednich w metodzie startActivity(Intent).
Narzędzia do kompilacji generują ostrzeżenie dotyczące startActivity(Intent) na podstawie adnotacji w odpowiedniej nazwie 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 parametrem @RequiresPermission.Read lub @RequiresPermission.Write podczas dodawania adnotacji do parametru metody. Jednak w przypadku uprawnień pośrednich nie należy używać adnotacji @RequiresPermission w połączeniu z adnotacjami uprawnień do odczytu lub uprawnień do zapisu.
Adnotacje dotyczące zwracanych wartości
Użyj adnotacji @CheckResult, aby sprawdzić, czy wynik lub zwracana wartość metody są rzeczywiście używane. Zamiast dodawać adnotację @CheckResult do każdej metody, która nie jest typu void, dodaj ją, aby wyjaśnić wyniki metod, które mogą być mylące.
Na przykład nowi programiści Javy często błędnie myślą, że <String>.trim() usuwa odstępy z oryginalnego ciągu znaków. Oznaczenie metody adnotacją @CheckResult powoduje, że wywołania <String>.trim(), w których element wywołujący nie wykonuje żadnych działań z wartością zwracaną przez metodę, są oznaczane flagą.
W przykładzie poniżej metoda checkPermissions() jest oznaczona adnotacją, aby sprawdzić, czy zwracana przez nią wartość jest rzeczywiście używana. Wskazuje też metodę enforcePermission() jako metodę, którą należy zasugerować 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ępująca wywołuje implementację super metody.
W poniższym przykładzie metoda onCreate() jest oznaczona adnotacją, aby zapewnić, że wszystkie zastępujące implementacje metod wywołują super.onCreate():
Kotlin
@CallSuper override fun onCreate(savedInstanceState: Bundle?) { }
Java
@CallSuper protected void onCreate(Bundle savedInstanceState) { }
Adnotacje Typedef
Adnotacje Typedef sprawdzają, czy dany parametr, wartość zwracana lub pole odwołuje się do określonego zestawu stałych. Umożliwiają też automatyczne uzupełnianie kodu, aby automatycznie oferować dozwolone stałe.
Użyj adnotacji @IntDef i @StringDef, aby utworzyć wyliczone adnotacje zbiorów liczb całkowitych i ciągów znaków do sprawdzania innych typów odwołań do kodu.
Adnotacje Typedef używają @interface do deklarowania nowego typu adnotacji wyliczeniowej.
Adnotacje @IntDef i @StringDef wraz z @Retention dodają adnotacje do nowej adnotacji i są niezbędne do zdefiniowania typu wyliczeniowego. Adnotacja @Retention(RetentionPolicy.SOURCE) informuje kompilator, aby nie przechowywał danych adnotacji wyliczeniowej w pliku .class.
W tym przykładzie pokazujemy, jak utworzyć adnotację, która sprawdza, czy wartość przekazana 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); }
Podczas kompilowania tego kodu generowane jest ostrzeżenie, jeśli parametr mode nie odwołuje się do jednej ze zdefiniowanych stałych (NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST lub NAVIGATION_MODE_TABS).
Połącz @IntDef i @IntRange, aby wskazać, że liczba całkowita może być danym zbiorem stałych lub wartością z zakresu.
Włącz łączenie stałych z flagami
Jeśli użytkownicy mogą łączyć dozwolone stałe z flagą (np. |, &, ^), możesz zdefiniować adnotację z atrybutem flag, aby sprawdzić, czy parametr lub zwracana wartość odwołuje się do prawidłowego wzorca.
W tym przykładzie tworzona jest adnotacja 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 tworzysz kod z flagą adnotacji, generowane jest ostrzeżenie, jeśli dekorowany parametr lub zwracana wartość nie odwołuje się do prawidłowego wzorca.
Zachowaj adnotację
Adnotacja @Keep gwarantuje, że adnotowana klasa lub metoda nie zostanie usunięta, gdy kod zostanie zminimalizowany w czasie kompilacji. Ta adnotacja jest zwykle dodawana do metod i klas, do których dostęp jest uzyskiwany przez refleksję, aby zapobiec traktowaniu kodu przez kompilator jako nieużywanego.
Uwaga: klasy i metody, które dodajesz do adnotacji za pomocą @Keep, zawsze pojawiają się w pliku APK aplikacji, nawet jeśli nigdy nie odwołujesz się do nich w logice aplikacji.
Aby zachować niewielki rozmiar aplikacji, zastanów się, czy konieczne jest zachowanie każdej adnotacji @Keep w aplikacji. Jeśli używasz refleksji, aby uzyskać dostęp do klasy lub metody z adnotacją, użyj warunku
-if w regułach ProGuard, określając klasę, która wykonuje wywołania refleksji.
Więcej informacji o tym, jak zminimalizować kod i określić, który kod nie ma zostać usunięty, znajdziesz w artykule Zmniejszanie, zaciemnianie i optymalizowanie aplikacji.
Adnotacje dotyczące widoczności kodu
Użyj tych adnotacji, aby określić widoczność konkretnych części kodu, takich jak metody, klasy, pola lub pakiety.
Udostępnianie kodu na potrzeby testów
Adnotacja @VisibleForTesting wskazuje, że metoda z adnotacją jest bardziej widoczna niż zwykle, aby można było ją przetestować. Ta adnotacja ma opcjonalny argument otherwise, który pozwala określić, jaka byłaby widoczność metody, gdyby nie trzeba było jej udostępniać na potrzeby testowania. Lint używa argumentu otherwise, aby wymusić zamierzoną widoczność.
W poniższym przykładzie myMethod() zwykle ma wartość private, ale w przypadku testów jest to package-private. W przypadku oznaczenia VisibleForTesting.PRIVATE lint wyświetla komunikat, jeśli ta metoda jest wywoływana spoza kontekstu dozwolonego przez dostęp private, np. z innej jednostki kompilacji.
Kotlin
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) fun myMethod() { ... }
Java
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) void myMethod() { ... }
Możesz też określić @VisibleForTesting(otherwise = VisibleForTesting.NONE), aby wskazać, że metoda istnieje tylko do testowania. Ta forma jest równoważna użyciu @RestrictTo(TESTS). Oba wykonują tę samą kontrolę lint.
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 do interfejsu API tylko do podklas.
Dostęp do tego interfejsu API mają tylko klasy, które rozszerzają klasę z adnotacją. Modyfikator protected w języku Java nie jest wystarczająco restrykcyjny, ponieważ umożliwia dostęp z niepowiązanych klas w tym samym pakiecie. Są też przypadki, gdy chcesz pozostawić metodę public, aby zachować elastyczność na przyszłość, ponieważ nigdy nie możesz utworzyć metody public, która wcześniej była protected i została zastąpiona, ale chcesz podać wskazówkę, że klasa jest przeznaczona do użycia tylko w ramach klasy lub z podklas.
Biblioteki
Użyj formularza adnotacji @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX), aby ograniczyć dostęp do interfejsu API tylko do swoich bibliotek.
Dostęp do interfejsu API z adnotacją może mieć tylko kod biblioteki. Dzięki temu możesz nie tylko uporządkować kod w dowolnej hierarchii pakietów, ale też udostępniać go w grupie powiązanych bibliotek. Ta opcja jest już dostępna w bibliotekach Jetpack, które zawierają dużo kodu implementacji, który nie jest przeznaczony do użytku zewnętrznego, ale musi być public, aby można go było udostępniać w różnych uzupełniających się bibliotekach Jetpack.
Testowanie
Użyj adnotacji @RestrictTo(RestrictTo.Scope.TESTS), aby uniemożliwić innym deweloperom dostęp do interfejsów API do testowania.
Dostęp do interfejsu API z adnotacjami może mieć tylko kod testowy. Uniemożliwi to innym deweloperom używanie interfejsów API do programowania, które są przeznaczone tylko do testowania.