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. 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 takim przypadku aplikacja może być renderowana nieprawidłowo lub wcale się nie uruchomić, nawet jeśli używasz inspekcji 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 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 za pomocą biblioteki adnotacji Jetpacka.
Do biblioteki możesz uzyskać dostęp 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
.
Dodawanie zależności biblioteki Jetpack Annotations
Biblioteka Jetpack Adnotacje została opublikowana w repozytorium Google Maven.
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' }
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 zależy od biblioteki adnotacji, więc być może masz już dostęp do adnotacji.
Pełną listę adnotacji dostępnych w repozytorium Jetpacka znajdziesz w pliku referencyjnym biblioteki adnotacji Jetpacka lub możesz użyć funkcji autouzupełniania, aby wyświetlić dostępne opcje 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 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ć 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
i @NonNull
, aby sprawdzić, czy dana zmienna, parametr lub wartość zwracana jest pusta. 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 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 @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 działa opcja dopuszczenia 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 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 umożliwia przeprowadzanie analizy możliwości wystąpienia wartości null, aby automatycznie wywnioskować i wstawić adnotacje dotyczące możliwości wystąpienia wartości null w kodzie. Analiza możliwości wystąpienia błędu skanuje umowy w hierarchiach metod w Twoim 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 null w wykrytych lokalizacjach.
Aby przeprowadzić analizę możliwości wystąpienia wartości null w Android Studio, wybierz Analizuj >
Przewiduj wartość 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: 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 drawable i string, 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 dla innych typów zasobów, takich jak @DrawableRes
, @DimenRes
, @ColorRes
i @InterpolatorRes
, można dodawać w tym samym formacie adnotacji i uruchamiać 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ą 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ą 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.
Adnotacje wątku są często używane do sprawdzania, czy metody lub klasy oznaczone adnotacją @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
i @Size
. 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 wartość parametru typu integer lub long mieści się w określonym zakresie. Z tego przykładu wynika, że parametr alpha
musi zawierać wartość 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. 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 weryfikacji tych właściwoś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 @Size(min=1)
sprawdza, czy kolekcja nie jest pusta, a @Size(3)
sprawdza, czy tablica zawiera dokładnie 3 wartości.
Ten przykład pokazuje, ż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 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;
W tym przykładzie wywołujący metodę copyImageFile()
musi mieć dostęp do odczytu z zewnętrznej pamięci masowej oraz dostęp do odczytu 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 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)
używa pośredniego uprawnienia 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 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 w klasie Intent
powodują ostrzeżenia o nieprawidłowym użyciu funkcji startActivity(Intent)
, gdy do metody przekazywany jest zamiar bez odpowiednich uprawnień, jak pokazano na rysunku 1.
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
parametrem @RequiresPermission.Read
lub @RequiresPermission.Write
podczas adnotowania 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 zwracanej wartości
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. Dodanie do metody oznaczenia @CheckResult
, która używa flag <String>.trim()
, gdy wywołujący nie robi nic z wartością zwracaną metody.
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
Aby sprawdzić, czy metoda zastępująca wywołuje implementację metody nadrzędnej, użyj adnotacji @CallSuper
.
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 Typedef
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 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
.
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
i @IntRange
, aby wskazać, że liczba całkowita może być określonym zbiorem stałych lub wartością w zakresie.
Włączanie łączenia stałych wartości 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 @Keep
zapewnia, ż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 opatrujesz adnotacjami za pomocą @Keep
, zawsze pojawiają się w pliku APK aplikacji, nawet jeśli nigdy nie odwołujesz się do tych klas i metod w logice aplikacji.
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 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
Aby oznaczyć widoczność określonych części kodu, takich jak metody, klasy, pola czy pakiety, użyj tych adnotacji.
Udostępnij kod do 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
. W przypadku oznaczenia VisibleForTesting.PRIVATE
lint wyświetla komunikat, jeśli ta metoda jest wywoływana spoza kontekstu dozwolonego przez dostęp private
, na przykład z innego modułu 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 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ą adnotowaną klasę. Modyfikator Java
protected
nie jest wystarczająco restrykcyjny, ponieważ zezwala na dostęp z niepowiązanych klas w tym samym pakiecie. Są też przypadki, w których chcesz pozostawić metodę public
, aby zapewnić sobie większą elastyczność w przyszłości, ponieważ nie możesz utworzyć metody protected
, która byłaby zastąpiona metodą public
, ale chcesz podać wskazówkę, że klasa jest przeznaczona tylko do użytku w ramach klasy lub tylko z podklas.
Biblioteki
Aby ograniczyć dostęp interfejsu API tylko do Twoich bibliotek, użyj formularza adnotacji @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
.
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 bibliotekach Jetpack z dużą ilością kodu implementacji, który nie jest przeznaczony do użytku zewnętrznego. Aby jednak móc ją udostępniać w różnych uzupełniających bibliotekach Jetpack, musi to być obiekt public
.
Testowanie
Aby uniemożliwić innym programistom dostęp do interfejsów API do testowania, 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ą być używane tylko do testów.