Korzystanie z narzędzi do sprawdzania kodu, takich jak lint, może pomóc w znalezieniu problemów i ulepszeniu kodu, ale narzędzia te mogą tylko w pewnym stopniu wywnioskować, co jest nie tak. Identyfikatory zasobów Androida, np. int
, służą do identyfikowania ciągów tekstowych, grafiki, kolorów i innych typów zasobów, więc narzędzia do sprawdzania nie mogą stwierdzić, czy w miejscu, w którym powinien być kolor, został podany zasób w postaci ciągu tekstowego. W takiej sytuacji aplikacja może być renderowana nieprawidłowo lub w ogóle nie działać, nawet jeśli sprawdzisz kod.
Adnotacje umożliwiają przekazywanie wskazówek do narzędzi do sprawdzania kodu, takich 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 pustego i konflikty typów zasobów.
Android obsługuje różne adnotacje za pomocą biblioteki adnotacji Jetpack.
Biblioteka jest dostępna w androidx.annotation
pakiecie.
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 przeprowadzania inspekcji kodu lub wykonywania zadania lint
.
Dodaj zależność biblioteki Jetpack Annotations
Biblioteka Jetpack Annotations jest publikowana w repozytorium Maven Google.
Aby dodać do projektu bibliotekę Jetpack Annotations, umieść ten wiersz w bloku dependencies
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' }
Jeśli używasz adnotacji we własnym module biblioteki, są one dołączane do artefaktu Android Archive (AAR) w formacie XML w pliku annotations.zip
. Dodanie zależności androidx.annotation
nie powoduje wprowadzenia zależności dla żadnych użytkowników biblioteki.
Uwaga: jeśli używasz innych bibliotek Jetpack, możesz nie musieć dodawać zależności androidx.annotation
. Wiele innych bibliotek Jetpack zależy od biblioteki adnotacji, więc możesz już mieć do nich dostęp.
Pełną listę adnotacji zawartych w repozytorium Jetpack znajdziesz w dokumentacji biblioteki adnotacji Jetpack lub używając funkcji autouzupełniania, aby wyświetlić dostępne opcje instrukcji import androidx.annotation.
.
Przeprowadzanie inspekcji kodu
Aby rozpocząć sprawdzanie kodu w Android Studio, które obejmuje weryfikację adnotacji i automatyczne sprawdzanie za pomocą narzędzia lint, 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 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 inspekcji lint znajdziesz w artykule Ulepszanie kodu za pomocą sprawdzania 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 Java, aby określić, czy wartości mogą być wartościami 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 wartość zwracana mają wartość null. Adnotacja @Nullable
wskazuje zmienną, parametr lub wartość zwracaną, która może mieć wartość null.
Symbol @NonNull
oznacza zmienną, parametr lub wartość zwracaną, która nie może mieć wartości null.
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, podczas kompilowania kodu generowane jest ostrzeżenie wskazujące konflikt wartości null. Próba odwołania się do wyniku metody oznaczonej adnotacją @Nullable
bez wcześniejszego sprawdzenia, czy wynik jest wartością null, generuje ostrzeżenie o wartości null. Używaj tylko @Nullable
w przypadku wartości zwracanej przez metodę, jeśli każde użycie metody musi być jawnie sprawdzane pod kątem wartości null.
Poniższy przykład pokazuje, jak działa możliwość przyjmowania wartości null. Przykładowy kod w języku Kotlin nie korzysta z adnotacji @NonNull
, ponieważ jest ona automatycznie dodawana do wygenerowanego kodu bajtowego, gdy określony jest typ niepusty. W przykładzie w języku Java użyto adnotacji @NonNull
w przypadku parametrów context
i attrs
, aby sprawdzić, czy przekazane wartości parametrów nie są wartościami 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 przeprowadzanie analizy dopuszczalności wartości null, aby automatycznie wywnioskować i wstawić w kodzie adnotacje dotyczące dopuszczalności wartości null. Analiza dopuszczalności wartości null skanuje kontrakty w hierarchiach metod w Twoim kodzie, aby wykryć:
- Metody wywoływania, 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ą przechowywać wartości null.
Następnie analiza automatycznie wstawia odpowiednie adnotacje o wartości null w wykrytych lokalizacjach.
Aby uruchomić analizę dopuszczalności wartości null w Android Studio, kliknij Analyze (Analizuj) > Infer Nullity (Wywnioskuj dopuszczalność wartości null). Android Studio wstawia adnotacje @Nullable
i @NonNull
w wykrytych lokalizacjach w kodzie. Po przeprowadzeniu analizy zerowej warto sprawdzić wstawione adnotacje.
Uwaga: podczas dodawania adnotacji o wartości null funkcja autouzupełniania może sugerować adnotacje IntelliJ
@Nullable
i @NotNull
zamiast adnotacji Androida o wartości null i może automatycznie importować odpowiednią bibliotekę. Narzędzie do lintowania w Android Studio sprawdza jednak tylko adnotacje o wartości null w Androidzie. Podczas weryfikacji adnotacji upewnij się, że projekt korzysta z adnotacji o wartości null w Androidzie, aby narzędzie do sprawdzania kodu mogło prawidłowo powiadamiać Cię podczas inspekcji kodu.
Adnotacje do zasobów
Weryfikacja typów zasobów może być przydatna, ponieważ odwołania do zasobów w Androidzie, 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, np. String
, może zostać przekazany do oczekiwanego typu odwołania int
, ale w rzeczywistości odwoływać 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 zostanie przekazane R.string
odwołanie.
Adnotacje dla innych typów zasobów, takich jak @DrawableRes
, @DimenRes
, @ColorRes
i @InterpolatorRes
, można dodawać w tym samym formacie adnotacji i uruchamiać podczas sprawdzania kodu.
Jeśli parametr obsługuje wiele typów zasobów, możesz umieścić w nim więcej niż jedną adnotację typu zasobu. 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ą reprezentującą kolor. 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ątków
Adnotacje wątków sprawdzają, czy metoda jest wywoływana z określonego typu wątku. Obsługiwane są te adnotacje do 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. W przypadku aplikacji systemowych z wieloma widokami w różnych wątkach wątek interfejsu może być inny niż wątek główny. 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ą to samo wymaganie dotyczące wątków, możesz dodać do klasy pojedynczą adnotację dotyczącą wątków, aby sprawdzić, czy wszystkie metody w klasie są wywoływane z tego samego typu wątku.
Często używa się adnotacji wątków do sprawdzania, 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ć wartości przekazywanych parametrów. Zarówno @IntRange
, jak i @FloatRange
są najbardziej przydatne w przypadku parametrów, w których użytkownicy mogą się pomylić.
Adnotacja @IntRange
sprawdza, czy wartość parametru typu integer lub long mieści się w określonym zakresie. Poniższy przykład wskazuje, że 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 zmiennoprzecinkowego lub podwójnej precyzji mieści się w określonym zakresie wartości zmiennoprzecinkowych. Poniższy przykład wskazuje, ż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żyć 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)
weryfikuje, 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 zweryfikować uprawnienia osoby wywołującej 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 opatrzona adnotacją wskazującą, ż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;
Poniższy przykład wymaga, aby wywołujący metodę copyImageFile()
miał dostęp do odczytu zarówno zewnętrznej pamięci masowej, jak i 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ść wymaganie dotyczące uprawnień w polu tekstowym, 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 dostawców treści, którzy wymagają oddzielnych 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 przekazanej do parametru metody, użyj
@RequiresPermission
w przypadku samego parametru bez podawania konkretnych uprawnień.
Na przykład metoda startActivity(Intent)
używa uprawnienia pośredniego w przypadku 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 wymusza wszelkie istniejące adnotacje z parametru w samej metodzie. W startActivity(Intent)
przykładzie adnotacje w klasie Intent
powodują wyświetlanie ostrzeżeń o nieprawidłowym użyciu startActivity(Intent)
, gdy do metody przekazywany jest zamiar bez odpowiednich uprawnień, jak pokazano na rysunku 1.

Rysunek 1. Ostrzeżenie wygenerowane na podstawie adnotacji dotyczącej uprawnień pośrednich w metodzie startActivity(Intent)
.
Narzędzia do kompilacji generują ostrzeżenie w przypadku 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
znakiem
@RequiresPermission.Read
lub @RequiresPermission.Write
podczas dodawania adnotacji do parametru metody. W przypadku uprawnień pośrednich symbolu @RequiresPermission
nie należy jednak używać w połączeniu z adnotacjami dotyczącymi uprawnień do odczytu lub zapisu.
Adnotacje wartości zwracanej
Użyj adnotacji @CheckResult
, aby sprawdzić, czy wynik lub wartość zwracana metody jest rzeczywiście używana. Zamiast dodawać adnotację @CheckResult
do każdej metody, która nie jest typu void, dodaj ją, aby wyjaśnić wyniki potencjalnie mylących metod.
Na przykład nowi programiści w Javie często błędnie myślą, że funkcja
<String>.trim()
usuwa białe znaki z oryginalnego ciągu znaków. Dodanie do metody adnotacji z flagą @CheckResult
oznacza użycie <String>.trim()
, gdy wywołujący nie robi nic z wartością zwracaną przez metodę.
W przykładzie poniżej użyto adnotacji w metodzie checkPermissions()
, aby sprawdzić, czy wartość zwracana przez tę metodę jest rzeczywiście używana. Wskazuje też enforcePermission()
metodę, którą należy zaproponować 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ę superklasy.
W poniższym przykładzie metoda onCreate()
jest opatrzona adnotacją, aby mieć pewność, że wszystkie implementacje zastępujące 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, dzięki czemu wyświetlają dozwolone stałe.
Używaj adnotacji @IntDef
i @StringDef
do tworzenia wyliczeniowych adnotacji zbiorów liczb całkowitych i ciągów znaków w celu weryfikowania innych typów odwołań do kodu.
Adnotacje typedef używają słowa kluczowego @interface
do deklarowania nowego typu adnotacji wyliczeniowej.
Adnotacje @IntDef
i @StringDef
oraz @Retention
służą do oznaczania nowej adnotacji i są niezbędne do zdefiniowania typu wyliczeniowego. Adnotacja @Retention(RetentionPolicy.SOURCE)
informuje kompilator, aby nie przechowywał wyliczonych danych adnotacji w pliku .class
.
W przykładzie poniżej 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 tworzenia 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 symbole @IntDef
i @IntRange
, aby wskazać, że liczba całkowita może być danym zestawem stałych lub wartością z zakresu.
Włączanie łączenia stałych z flagami
Jeśli użytkownicy mogą łączyć dozwolone stałe z flagą (np. |
, &
, ^
itp.), możesz zdefiniować adnotację z atrybutem flag
, aby sprawdzić, czy parametr lub wartość zwracana odwołuje się do prawidłowego wzorca.
W tym przykładzie tworzymy 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 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
sprawia, że adnotowane zajęcia lub metoda nie są usuwane, gdy kod jest minimalizowany w czasie kompilacji. Ta adnotacja jest zwykle dodawana do metod i klas, do których uzyskuje się dostęp za pomocą odbicia, aby zapobiec traktowaniu kodu przez kompilator jako nieużywanego.
Ostrzeżenie: klasy i metody, które oznaczasz za pomocą adnotacji @Keep
, zawsze pojawiają się w pliku APK aplikacji, nawet jeśli nigdy nie odwołujesz się do nich w logice aplikacji.
Aby zmniejszyć rozmiar aplikacji, zastanów się, czy konieczne jest zachowanie każdej adnotacji @Keep
w aplikacji. Jeśli używasz odbicia do uzyskiwania dostępu do klasy lub metody z adnotacjami, użyj warunku
-if
w regułach ProGuard, określając klasę, która wykonuje wywołania odbicia.
Więcej informacji o tym, jak zminimalizować kod i określić, które fragmenty nie mają być usuwane, znajdziesz w artykule Zmniejszanie, zaciemnianie i optymalizowanie aplikacji.
Adnotacje dotyczące widoczności kodu
Używaj tych adnotacji, aby oznaczać widoczność określonych części kodu, takich jak metody, klasy, pola lub pakiety.
Udostępnianie kodu do testowania
Adnotacja
@VisibleForTesting
wskazuje, że adnotowana metoda 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 tym przykładzie myMethod()
to zwykle private
, ale w przypadku testów jest to package-private
. Oznaczenie VisibleForTesting.PRIVATE
sprawia, że narzędzie 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 na potrzeby testowania. Ten formularz jest taki sam jak w przypadku użycia @RestrictTo(TESTS)
. Oba wykonują to samo sprawdzanie.
Ograniczanie interfejsu API
Adnotacja @RestrictTo
oznacza, że dostęp do danego 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.
Tylko klasy rozszerzające klasę z adnotacjami mogą uzyskać dostęp do tego interfejsu API. Modyfikator Java protected
nie jest wystarczająco restrykcyjny, ponieważ umożliwia dostęp z niepowiązanych klas w tym samym pakiecie. Istnieją też przypadki, w których chcesz pozostawić metodę public
, aby zapewnić sobie większą elastyczność w przyszłości, ponieważ nie możesz nigdy utworzyć wcześniej protected
i zastąpić metody public
, ale chcesz zasugerować, że klasa jest przeznaczona do użycia tylko w klasie lub w podklasach.
Biblioteki
Użyj formularza adnotacji @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
, aby ograniczyć dostęp do interfejsu API tylko do swoich bibliotek.
Tylko kod biblioteki może mieć dostęp do interfejsu API z adnotacjami. Dzięki temu możesz nie tylko organizować 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 nieprzeznaczonego do użytku zewnętrznego, ale który musi być public
, aby można było udostępniać go w różnych uzupełniających się bibliotekach Jetpack.
Testowanie
Użyj formularza adnotacji @RestrictTo(RestrictTo.Scope.TESTS)
, aby uniemożliwić innym programistom dostęp do interfejsów API testowania.
Dostęp do interfejsu API z adnotacjami ma tylko kod testowy. Uniemożliwi to innym programistom korzystanie z interfejsów API do celów programistycznych, jeśli zamierzasz używać ich tylko do testowania.