Korzystanie z narzędzi do inspekcji kodu, takich jak lint, może pomóc w wykrywaniu problemów i ulepszaniu kodu, ale narzędzia do inspekcji nie są w stanie wyciągnąć zbyt wielu wniosków. Na przykład identyfikatory zasobów Androida używają wartości int
do identyfikowania ciągów znaków, grafik, kolorów i innych typów zasobów, więc narzędzia do sprawdzania 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 możesz dołączać do zmiennych, parametrów i wartości zwracanych, aby sprawdzać wartości zwracane przez metody, przekazywane parametry, zmienne lokalne i pola. W połączeniu z narzędziami do sprawdzania kodu adnotacje mogą pomóc w wykrywaniu problemów takich jak wyjątki związane z wskaźnikiem null i konflikty typu zasobu.
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 do biblioteki lub aplikacji zależność androidx.annotation:annotation
. Dodane adnotacje są sprawdzane podczas inspekcji kodu lub zadania lint
.
Dodaj zależność biblioteki Jetpack Annotations
Biblioteka Jetpack Annotations jest publikowana w repozytorium Maven Google.
Aby dodać do projektu bibliotekę Jetpack Anotations, dodaj ten wiersz do bloku dependencies
w pliku build.gradle
lub build.gradle.kts
:
Kotlin
dependencies { implementation("androidx.annotation:annotation:1.9.1") }
Groovy
dependencies { implementation 'androidx.annotation:annotation:1.9.1' }
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 zależności dla użytkowników 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 konflikcie, aby sygnalizować potencjalne problemy, w których Twój kod jest niezgodny z adnotacjami, oraz sugerować możliwe rozwiązania.
Możesz też wymusić adnotacje, uruchamiając zadanie lint
za pomocą wiersza poleceń. Chociaż może to być przydatne do oznaczania problemów z serwerem ciągłej integracji, zadanie lint
nie wymusza adnotacji nullości (opisanych w następnej sekcji); robi to tylko Android Studio. Więcej informacji o włączaniu i uruchamianiu kontroli zgodności kodu znajdziesz w artykule Poprawianie kodu za pomocą kontroli zgodności kodu.
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 być pusta.
@NonNull
wskazuje zmienną, parametr lub wartość zwracaną, która nie może być pusta.
Jeśli na przykład zmienna lokalna zawierająca wartość null jest przekazywana jako parametr do metody z dołączoną adnotacją @NonNull
, kompilacja kodu powoduje ostrzeżenie o konflikcie z wartością inną niż null. Próba odwołania się do wyniku metody oznaczonej symbolem @Nullable
bez wcześniejszego sprawdzenia, czy wynik jest pusty, powoduje ostrzeżenie o wartości null. Używaj @Nullable
do wartości zwracanej przez metodę tylko wtedy, gdy każde użycie metody musi być wyraźnie sprawdzane pod kątem wartości null.
Poniższy przykład pokazuje, jak działa opcja null. Przykładowy kod Kotlina nie korzysta z adnotacji @NonNull
, ponieważ jest ona automatycznie dodawana do wygenerowanego kodu bajtowego, gdy określony jest typ, który nie może być pusty. Przykład w języku Java korzysta z adnotacji @NonNull
w przypadku parametrów context
i attrs
, aby sprawdzić, czy przekazane wartości parametrów nie są puste. Sprawdza też, czy metoda onCreateView()
nie zwraca wartości null:
Kotlin
... /** Annotation not used because of the safe-call operator(?)**/ override fun onCreateView( name: String?, context: Context, attrs: AttributeSet ): View? { ... } ...
Java
import androidx.annotation.NonNull; ... /** Add support for inflating the <fragment> tag. **/ @NonNull @Override public View onCreateView(String name, @NonNull Context context, @NonNull AttributeSet attrs) { ... } ...
Analiza dopuszczalności
Android Studio umożliwia przeprowadzanie analizy możliwości wystąpienia wartości null, aby automatycznie wywnioskować i wstawić adnotacje nullości 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ą mieć 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, kliknij Analizuj >
Przewiduj wartość null. Android Studio wstawia adnotacje Androida @Nullable
i @NonNull
w wykrytych lokalizacjach w Twoim kodzie. Po przeprowadzeniu analizy pustych wartości warto zweryfikować wstrzyknięte adnotacje.
Uwaga: podczas dodawania adnotacji nullości autouzupełnianie może sugerować adnotacje IntelliJ
@Nullable
i
@NotNull
zamiast adnotacji nullości na Androida. Może też automatycznie zaimportować odpowiednią bibliotekę. Sprawdzacz lint w Android Studio sprawdza jednak tylko adnotacje null na Androida. Podczas sprawdzania adnotacji sprawdź, czy Twój projekt używa adnotacji null na Androida, aby sprawdzacz lint mógł odpowiednio poinformować Cię o błędach podczas inspekcji kodu.
Adnotacje zasobów
Walidowanie typów zasobów może być przydatne, ponieważ odwołania do zasobów w Androidzie, takich jak zasoby 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 faktycznie 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 parametr obsługuje wiele typów zasobów, możesz dodać do niego 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ć atrybutu @ColorRes
, aby określić, że parametr powinien być zasobem koloru, liczba całkowita koloru (w formacie RRGGBB
lub AARRGGBB
) nie jest rozpoznawana jako zasób koloru. Zamiast tego użyj adnotacji @ColorInt
, aby wskazać, że parametr musi być liczbą całkowitą koloru. Narzędzia do kompilacji będą oznaczać nieprawidłowy kod, który przekazuje do metody opatrzonej adnotacjami identyfikator zasobu koloru, np. android.R.color.black
, zamiast koloru w postaci liczby całkowitej.
Adnotacje wątków
Adnotacje wątku sprawdzają, czy metoda jest wywoływana z określonego typu wątku. Obsługiwane są te adnotacje wątku:
Narzędzia do 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 może się jednak zdarzyć, że wątek interfejsu użytkownika jest inny niż główny wątek. Dlatego metody powiązane z hierarchią widoku aplikacji należy opatrzyć adnotacją @UiThread
, a metody powiązane z cyklem życia aplikacji – adnotacją @MainThread
.
Jeśli wszystkie metody w klasie mają te same wymagania dotyczące wątków, możesz dodać do klasy pojedynczą adnotację wątku, aby sprawdzić, czy wszystkie metody w klasie są wywoływane z tego samego typu wątku.
Najczęstszym zastosowaniem adnotacji wątku jest sprawdzanie, czy metody lub klasy opatrzone 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 przypadku użytkownicy mogą podać nieprawidłowy zakres.
Adnotacja @IntRange
sprawdza, czy wartość parametru typu integer lub long mieści się w określonym zakresie. 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 typu float lub double mieści się w określonym zakresie wartości zmiennoprzecinkowych. Z tego 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. Adnotację @Size
można wykorzystać 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 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.
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 metoda setWallpaper()
jest opatrzona adnotacją, która wskazuje, że wywołujący tę metodę musi mieć uprawnienie permission.SET_WALLPAPERS
:
Kotlin
@RequiresPermission(Manifest.permission.SET_WALLPAPER) @Throws(IOException::class) abstract fun setWallpaper(bitmap: Bitmap)
Java
@RequiresPermission(Manifest.permission.SET_WALLPAPER) public abstract void setWallpaper(Bitmap bitmap) throws IOException;
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ń dotyczących intencji umieść wymagane uprawnienia w polu ciągu znaków, 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ń 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 używasz uprawnień pośrednich, narzędzia do kompilacji przeprowadzają analizę przepływu danych, aby sprawdzić, czy argument przekazany do metody zawiera adnotacje @RequiresPermission
. Następnie stosuje ona wszystkie 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. W przypadku uprawnień pośrednich @RequiresPermission
nie należy jednak używać w połączeniu z adnotacją uprawnień do odczytu ani uprawnień do 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ę niepusta, dodaj adnotację, aby wyjaśnić wyniki potencjalnie mylących metod.
Na przykład początkujący programiści Java często błędnie uważają, że znak <String>.trim()
usuwa spacje z pierwotnego ciągu znaków. Dodawanie adnotacji do metody za pomocą flag @CheckResult
, w której wywołujący nie robi nic z wartością zwracaną metody, wykorzystuje <String>.trim()
.
W tym przykładzie dodaliśmy adnotację do metody checkPermissions()
, aby sprawdzić, czy odwołuje się ona do wartości zwracanej. 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 typu
Adnotacje typu definiują, czy dany parametr, zwracana wartość lub pole odwołuje się do określonego zbioru stałych. Umożliwiają też automatyczne uzupełnianie kodu, aby automatycznie oferować dozwolone stałe.
Użyj adnotacji @IntDef
i @StringDef
, aby utworzyć adnotacje z wyliczeniami zbiorów liczb całkowitych i ciągów znaków, które służą do sprawdzania innych typów odwołań do kodu.
Adnotacje typu „Typedef” używają instrukcji @interface
do deklarowania nowego typu adnotacji z wyliczeniem.
Adnotacje @IntDef
i @StringDef
wraz z adnotacją @Retention
adnotują nową adnotację i są niezbędne do zdefiniowania typu wyliczeniowego. Adnotacja @Retention(RetentionPolicy.SOURCE)
informuje kompilator, aby nie przechowywać danych adnotacji za pomocą enumeracji w pliku .class
.
W tym przykładzie pokazano, jak utworzyć adnotację, która sprawdza, czy wartość przekazana jako parametr metody odwołuje się do jednej z zdefiniowanych stałych:
Kotlin
import androidx.annotation.IntDef //... // Define the list of accepted constants and declare the NavigationMode annotation. @Retention(AnnotationRetention.SOURCE) @IntDef(NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS) annotation class NavigationMode // Declare the constants. const val NAVIGATION_MODE_STANDARD = 0 const val NAVIGATION_MODE_LIST = 1 const val NAVIGATION_MODE_TABS = 2 abstract class ActionBar { // Decorate the target methods with the annotation. // Attach the annotation. @get:NavigationMode @setparam:NavigationMode abstract var navigationMode: Int }
Java
import androidx.annotation.IntDef; //... public abstract class ActionBar { //... // Define the list of accepted constants and declare the NavigationMode annotation. @Retention(RetentionPolicy.SOURCE) @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}) public @interface NavigationMode {} // Declare the constants. public static final int NAVIGATION_MODE_STANDARD = 0; public static final int NAVIGATION_MODE_LIST = 1; public static final int NAVIGATION_MODE_TABS = 2; // Decorate the target methods with the annotation. @NavigationMode public abstract int getNavigationMode(); // Attach the annotation. public abstract void setNavigationMode(@NavigationMode int mode); }
Podczas kompilowania tego kodu generowane jest ostrzeżenie, jeśli parametr mode
nie odwołuje się do jednej z zdefiniowanych stałych (NAVIGATION_MODE_STANDARD
, NAVIGATION_MODE_LIST
lub NAVIGATION_MODE_TABS
).
Połącz @IntDef
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 jako nieużywanego przez kompilator.
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 konieczne jest zachowanie w niej każdej adnotacji @Keep
. Jeśli używasz odblasku, aby uzyskać dostęp do adnotowanej klasy lub metody, użyj w regułach ProGuard wyrażenia warunkowego
-if
, określając klasę, która wykonuje wywołania odblasku.
Więcej informacji o minifikacji kodu i określaniu, którego kodu nie należy usuwać, znajdziesz w artykule Zmniejsz, zaciemnij i zoptymalizuj aplikację.
Adnotacje dotyczące widoczności kodu
Aby oznaczyć widoczność określonych części kodu, takich jak metody, klasy, pola czy pakiety, użyj tych adnotacji.
Udostępnianie kodu na potrzeby testowania
Adnotacja @VisibleForTesting
wskazuje, że adnotowana metoda jest bardziej widoczna niż zwykle, co ułatwia jej testowanie. Ta adnotacja ma opcjonalny argument otherwise
, który pozwala określić, jaka byłaby widoczność metody, gdyby nie potrzeba jej wyświetlania 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ć wartość @VisibleForTesting(otherwise = VisibleForTesting.NONE)
, aby wskazać, że metoda istnieje tylko do testowania. Ten formularz jest taki sam jak @RestrictTo(TESTS)
. Oba wykonują te same kontrole.
Ograniczanie interfejsu API
Adnotacja @RestrictTo
wskazuje, że dostęp do oznaczonego interfejsu API (pakietu, klasy lub metody) jest ograniczony w następujący sposób:
Podklasy
Aby ograniczyć dostęp do interfejsu API tylko do podklas, użyj formularza adnotacji @RestrictTo(RestrictTo.Scope.SUBCLASSES)
.
Dostęp do tego interfejsu API mają tylko klasy, które rozszerzają 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)
.
Do interfejsu API z adnotacjami może mieć dostęp tylko kod Twojej biblioteki. Dzięki temu możesz nie tylko porządkować kod w dowolnej hierarchii pakietu, ale też udostępniać go grupie powiązanych bibliotek. Ta opcja jest już dostępna w przypadku bibliotek Jetpacka, które zawierają dużo kodu implementacji, który nie jest przeznaczony do użytku zewnętrznego, ale musi być public
, aby udostępnić go w różnych uzupełniających bibliotekach Jetpacka.
Testowanie
Aby uniemożliwić innym programistom dostęp do interfejsów API do testowania, użyj formularza adnotacji @RestrictTo(RestrictTo.Scope.TESTS)
.
Do interfejsu API z adnotacjami dostęp ma tylko kod testowy. Zapobiega to używaniu przez innych programistów interfejsów API do celów programistycznych, które mają służyć tylko do testowania.