Ulepsz inspekcję kodu za pomocą adnotacji

Narzędzia do inspekcji kodu, takie jak lint, mogą pomóc Ci znaleźć problemy i ulepszyć kod, ale narzędzia kontrolne są w stanie wywnioskować tylko tak dużo. Identyfikatory zasobów Androida na przykład używają int do identyfikowania ciągów znaków, grafiki, kolorów i innych typów zasobów, więc narzędzia kontrolne nie będą w stanie określić, kiedy zasób tekstowy jest w którym należy określić kolor. W takiej sytuacji aplikacja może renderować się nieprawidłowo lub w ogóle nie działać, nawet jeśli użyjesz inspekcji kodu.

Adnotacje umożliwiają podawanie wskazówek dotyczących narzędzi do inspekcji kodu, takich jak lint, które pomagają w wykrywaniu tych bardziej skomplikowanych problemów z kodem. Adnotacje są dodawane jako tagi metadanych, które umieszczasz w zmiennych, parametrach i zwracanych wartościach, aby sprawdzać wartości zwracanych metod, przekazanych parametrów, zmiennych lokalnych i pól. Adnotacje używane z narzędziami do inspekcji kodu mogą pomóc Ci w wykrywaniu problemów, takich jak wyjątki wskaźnika null i konflikty typów zasobów.

Android obsługuje różne adnotacje z 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 dla Kotlin albo konfiguracji zależności annotationProcessor w Javie.

Dodaj adnotacje do projektu

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

Dodawanie zależności od biblioteki adnotacji Jetpack

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

Kotlin

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

Odlotowy

dependencies {
    implementation 'androidx.annotation:annotation:1.7.1'
}
Następnie na pasku narzędzi lub w powiadomieniu o synchronizacji kliknij Synchronizuj teraz.

Jeśli używasz adnotacji w module swojej biblioteki, są one dołączane w pliku annotations.zip jako część artefaktu Android Archive (AAR) w formacie XML. Dodanie zależności androidx.annotation nie wprowadza zależności w przypadku żadnych dodatkowych użytkowników biblioteki.

Uwaga: jeśli używasz innych bibliotek Jetpack, dodanie zależności androidx.annotation może nie być konieczne. Wiele innych bibliotek Jetpack korzysta z biblioteki adnotacji, dlatego możesz mieć już do nich dostęp.

Pełną listę adnotacji znajdujących się w repozytorium Jetpack znajdziesz w dokumentacji biblioteki adnotacji Jetpack lub przy użyciu funkcji autouzupełniania, która pozwala wyświetlić opcje dostępne dla instrukcji import androidx.annotation..

Uruchamiaj inspekcje kodu

Aby rozpocząć inspekcję kodu w Android Studio, która obejmuje weryfikację adnotacji i automatyczne sprawdzanie lintek, w menu wybierz Analizuj > Zbadaj kod. Android Studio wyświetla komunikaty o konfliktach, aby wskazywać potencjalne problemy, w których Twój kod koliduje z adnotacjami, i sugerować możliwe rozwiązania.

Możesz też wymusić stosowanie adnotacji, uruchamiając zadanie lint za pomocą wiersza poleceń. Może to być przydatne przy zgłaszaniu problemów z serwerem ciągłej integracji, jednak zadanie lint nie wymusza adnotacji o wartości null (opisanych w kolejnej sekcji). Tę funkcję robi tylko Android Studio. Więcej informacji o włączaniu i przeprowadzaniu kontroli lint znajdziesz w artykule Ulepszanie kodu przy użyciu sprawdzania lint.

Chociaż konflikty adnotacji generują ostrzeżenia, te ostrzeżenia nie uniemożliwiają kompilacji aplikacji.

Adnotacje o wartości null

Adnotacje o wartości null mogą być przydatne w kodzie Java, by wymusić stosowanie wartości null. Są one mniej przydatne w kodzie Kotlin, ponieważ Kotlin ma wbudowane reguły dopuszczalności wartości null, które są egzekwowane podczas kompilacji.

Dodaj adnotacje @Nullable i @NonNull, aby sprawdzić wartość null danej zmiennej, parametru lub zwracanej wartości. Adnotacja @Nullable wskazuje zmienną, parametr lub wartość zwracaną, które mogą mieć wartość null. @NonNull wskazuje zmienną, parametr lub zwracaną wartość, które nie mogą mieć wartości null.

Jeśli np. zmienna lokalna zawierająca wartość null jest przekazywana jako parametr do metody z dołączoną adnotacją @NonNull do tego parametru, kompilacja kodu generuje ostrzeżenie wskazujące konflikt niezawierający wartości null. Również próba odwołania się do wyniku metody oznaczonej przez @Nullable bez uprzedniego sprawdzenia, czy wynik ma wartość null, generuje ostrzeżenie o braku wartości. Funkcji @Nullable w wartości zwracanej przez metodę należy używać tylko wtedy, gdy każde jej użycie musi być wyraźnie zaznaczone jako null.

Przykład poniżej pokazuje działanie funkcji null (dopuszczalność wartości null). Przykładowy kod Kotlin nie korzysta z adnotacji @NonNull, ponieważ jest ona automatycznie dodawana do wygenerowanego kodu bajtowego, gdy określony jest typ niedopuszczalny do wartości null. W przykładzie w języku Java użyto adnotacji @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 wartości null, co pozwala automatycznie wnioskować i wstawiać w kodzie adnotacje o wartości null. Analiza dopuszczalności wartości null skanuje umowy w hierarchii metod w 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ą zawierać wartości null.

Analiza automatycznie wstawia do wykrytych lokalizacji odpowiednie adnotacje o wartości null.

Aby przeprowadzić w Android Studio analizę wartości null, wybierz Analiza > Wnioskowanie nullity. Android Studio wstawia adnotacje @Nullable i @NonNull na Androidzie w wykrytych lokalizacjach w kodzie. Po przeprowadzeniu analizy null warto sprawdzić wstrzyknięte adnotacje.

Uwaga: podczas dodawania adnotacji o wartości null autouzupełnianie może proponować adnotacje IntelliJ @Nullable i @NotNull zamiast adnotacji null w Androidzie, a także automatycznie importować odpowiednią bibliotekę. Jednak narzędzie Android Studio do sprawdzania lintów wyszukuje tylko puste adnotacje Androida. Weryfikując adnotacje, sprawdź, czy Twój projekt korzysta z adnotacji o wartości null Androida, aby narzędzie do sprawdzania lint mogło Cię odpowiednio powiadamiać podczas inspekcji kodu.

Adnotacje do zasobów

Warto sprawdzić typy zasobów, ponieważ Android odnosi się do takich zasobów jak zasoby drawable czy string, czyli w liczbach całkowitych.

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ła się do innego typu zasobu, takiego jak zasób R.string.

Dodaj np. adnotacje @StringRes, aby sprawdzić, czy parametr zasobu zawiera odwołanie do R.string, jak w tym przykładzie:

Kotlin

abstract fun setTitle(@StringRes resId: Int)

Java

public abstract void setTitle(@StringRes int resId)

Podczas inspekcji kodu adnotacja generuje ostrzeżenie, jeśli w parametrze nie zostanie przekazane odwołanie R.string.

Adnotacje dotyczące innych typów zasobów, takich jak @DrawableRes, @DimenRes, @ColorRes i @InterpolatorRes, można dodawać w tym samym formacie adnotacji i uruchamiać je podczas inspekcji kodu.

Jeśli parametr obsługuje wiele typów zasobów, możesz umieścić dla niego więcej niż jedną adnotację dotyczącą typu zasobu. Użyj @AnyRes, aby wskazać, że parametr z adnotacjami może być dowolnym typem zasobu R.

Mimo że możesz użyć @ColorRes, aby określić, że parametr powinien być zasobem koloru, liczba całkowita koloru (w formacie RRGGBB lub AARRGGBB) nie zostanie rozpoznana jako zasób koloru. Zamiast tego użyj adnotacji @ColorInt, aby wskazać, że parametr musi być liczbą całkowitą koloru. Narzędzia do kompilacji oznaczą nieprawidłowy kod, który przekazuje do metod z adnotacjami identyfikator zasobu koloru, np. android.R.color.black, a nie liczbę całkowitą koloru.

Adnotacje do wątków

Adnotacje wątku sprawdzają, czy metoda jest wywoływana z określonego typu wątku. Obsługiwane są te adnotacje wątkach:

Narzędzia do tworzenia traktują adnotacje @MainThread i @UiThread jako wymienne, więc można wywoływać metody @UiThread z metod @MainThread i odwrotnie. Wątek UI może się jednak różnić od wątku głównego w przypadku aplikacji systemowych z wieloma widokami w różnych wątkach. Dlatego należy dodawać adnotacje do metod powiązanych z hierarchią widoków aplikacji za pomocą atrybutu @UiThread oraz metody @MainThread powiązane z cyklem życia aplikacji.

Jeśli wszystkie metody w klasie mają ten sam wymóg dotyczący wątków, możesz dodać do klasy pojedynczą adnotację dotyczącą wątku, aby sprawdzić, czy wszystkie metody w klasie są wywoływane z tego samego typu wątku.

Typowym zastosowaniem adnotacji do wątków jest sprawdzanie, czy metody lub klasy z adnotacją @WorkerThread są wywoływane wyłącznie z odpowiedniego wątku w tle.

Adnotacje o ograniczeniach wartości

Za pomocą adnotacji @IntRange, @FloatRange i @Size możesz sprawdzać wartości przekazywanych parametrów. Zarówno @IntRange, jak i @FloatRange są najbardziej przydatne w przypadku stosowania w przypadku parametrów, w których przypadku użytkownicy prawdopodobnie będą popełniać błędy w zakresie zakresu.

Adnotacja @IntRange sprawdza, czy wartość parametru liczby całkowita lub o długości mieści się w określonym zakresie. Poniższy przykład wskazuje, że parametr alpha musi zawierać liczbę całkowitą od 0 do 255:

Kotlin

fun setAlpha(@IntRange(from = 0, to = 255) alpha: Int) { ... }

Java

public void setAlpha(@IntRange(from=0,to=255) int alpha) { ... }

Adnotacja @FloatRange sprawdza, czy wartość parametru liczby zmiennoprzecinkowej czy liczby zmiennoprzecinkowej mieści się w określonym zakresie wartości zmiennoprzecinkowych. W tym przykładzie 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żyć do sprawdzenia tych właściwości:

  • Rozmiar minimalny, np. @Size(min=2)
  • Rozmiar maksymalny, np. @Size(max=2)
  • Dokładny rozmiar, np. @Size(2)
  • Liczba, której rozmiar musi być wielokrotnością liczby, 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 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ń

Aby zweryfikować uprawnienia elementu wywołującego metodę, użyj adnotacji @RequiresPermission. Aby sprawdzić dane uprawnienie na liście prawidłowych uprawnień, użyj atrybutu anyOf. Aby sprawdzić zestaw uprawnień, użyj atrybutu allOf. W podanym niżej przykładzie wskazano 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;

Poniższy przykład wymaga, aby element wywołujący metodę copyImageFile() miał uprawnienia do odczytu w pamięci zewnętrznej i uprawnienia do odczytu metadanych lokalizacji w kopiowanym obrazie:

Kotlin

@RequiresPermission(allOf = [
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.ACCESS_MEDIA_LOCATION
])
fun copyImageFile(dest: String, source: String) {
    ...
}

Java

@RequiresPermission(allOf = {
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.ACCESS_MEDIA_LOCATION})
public static final void copyImageFile(String dest, String source) {
    //...
}

W przypadku uprawnień do intencji umieść wymagane uprawnienia w polu ciągu tekstowym, 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";

Aby przyznać uprawnienia dotyczące dostawców treści, którzy potrzebują osobnych uprawnień do odczytu i zapisu, umieść każde z wymagań dotyczących 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 parametrowi metody, użyj @RequiresPermission w samym parametrze bez wymieniania konkretnych uprawnień. Na przykład metoda startActivity(Intent) korzysta z pośrednich uprawnień w intencji przekazywanej do metody:

Kotlin

abstract fun startActivity(@RequiresPermission intent: Intent, bundle: Bundle?)

Java

public abstract void startActivity(@RequiresPermission Intent intent, @Nullable Bundle)

Gdy korzystasz z uprawnień pośrednich, narzędzia do kompilacji przeprowadzają analizę przepływu danych, aby sprawdzić, czy argument przekazany do metody zawiera adnotacje @RequiresPermission. Następnie wymuszają one stosowanie wszelkich istniejących adnotacji w parametrze w samej metodzie. W przykładzie startActivity(Intent) adnotacje w klasie Intent powodują ostrzeżenia o nieprawidłowym użyciu funkcji startActivity(Intent) po przekazaniu do metody intencji bez odpowiednich uprawnień, jak widać na ilustracji 1.

Rysunek 1. Ostrzeżenie wygenerowane na podstawie adnotacji uprawnień pośrednich w metodzie startActivity(Intent).

Narzędzia do kompilacji generują ostrzeżenie na startActivity(Intent) z adnotacji dotyczącej odpowiedniej nazwy działania intencji w klasie Intent:

Kotlin

@RequiresPermission(Manifest.permission.CALL_PHONE)
const val ACTION_CALL = "android.intent.action.CALL"

Java

@RequiresPermission(Manifest.permission.CALL_PHONE)
public static final String ACTION_CALL = "android.intent.action.CALL";

W razie potrzeby podczas dodawania adnotacji do parametru metody możesz zastąpić @RequiresPermission wartością @RequiresPermission.Read lub @RequiresPermission.Write. W przypadku uprawnień pośrednich nie należy jednak używać uprawnień @RequiresPermission w połączeniu z adnotacjami o uprawnieniach do odczytu ani zapisu.

Adnotacje wartości zwracanych

Za pomocą adnotacji @CheckResult możesz sprawdzić, czy wynik lub wartość zwróconej metody są rzeczywiście używane. Zamiast dodawać adnotacje do każdej nieważnej metody @CheckResult, dodaj adnotację, aby wyjaśnić wyniki stosowania metod potencjalnie wprowadzających w błąd.

Na przykład nowi deweloperzy w języku Java często mylnie myślą, że właściwość <String>.trim() usuwa odstępy z pierwotnego ciągu znaków. Dodawanie adnotacji metody za pomocą flag @CheckResult do użycia klasy <String>.trim(), gdy element wywołujący nie robi nic z wartością zwrotną metody.

W przykładzie poniżej opisujemy metodę checkPermissions() sprawdzającą, czy zwracana jest wartość. Jest też nazywana metodą enforcePermission(), która jest proponowana deweloperowi jako zamiennik:

Kotlin

@CheckResult(suggest = "#enforcePermission(String,int,int,String)")
abstract fun checkPermission(permission: String, pid: Int, uid: Int): Int

Java

@CheckResult(suggest="#enforcePermission(String,int,int,String)")
public abstract int checkPermission(@NonNull String permission, int pid, int uid);

Adnotacje CallSuper

Użyj adnotacji @CallSuper, aby sprawdzić, czy metoda zastępowania wywołuje superimplementację metody.

W tym przykładzie wskazano metodę onCreate(), aby zagwarantować, że każda implementacja metody zastępowania wywołuje metodę super.onCreate():

Kotlin

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

Java

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

Adnotacje Typedef

Adnotacje Typedef sprawdzają, czy określony parametr, zwracana wartość lub pole odwołuje się do określonego zestawu stałych. Włączają też uzupełnianie kodu, aby automatycznie proponować dozwolone wartości stałe.

Za pomocą adnotacji @IntDef i @StringDef możesz tworzyć policzone adnotacje ze zbiorami liczb całkowitych i ciągów znaków w celu weryfikacji innych typów odwołań do kodu.

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

Poniższy przykład pokazuje kroki, jak utworzyć adnotację, która sprawdza, czy wartość przekazywana jako parametr metody odwołuje się do jednej ze zdefiniowanych stałych:

Kotlin

import androidx.annotation.IntDef
//...
// Define the list of accepted constants and declare the NavigationMode annotation.
@Retention(AnnotationRetention.SOURCE)
@IntDef(NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS)
annotation class NavigationMode

// Declare the constants.
const val NAVIGATION_MODE_STANDARD = 0
const val NAVIGATION_MODE_LIST = 1
const val NAVIGATION_MODE_TABS = 2

abstract class ActionBar {

    // Decorate the target methods with the annotation.
    // Attach the annotation.
    @get:NavigationMode
    @setparam:NavigationMode
    abstract var navigationMode: Int

}

Java

import androidx.annotation.IntDef;
//...
public abstract class ActionBar {
    //...
    // Define the list of accepted constants and declare the NavigationMode annotation.
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
    public @interface NavigationMode {}

    // Declare the constants.
    public static final int NAVIGATION_MODE_STANDARD = 0;
    public static final int NAVIGATION_MODE_LIST = 1;
    public static final int NAVIGATION_MODE_TABS = 2;

    // Decorate the target methods with the annotation.
    @NavigationMode
    public abstract int getNavigationMode();

    // Attach the annotation.
    public abstract void setNavigationMode(@NavigationMode int mode);
}

Gdy kompilujesz ten kod, jest generowane 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 właściwości @IntDef i @IntRange, aby wskazać, że liczba całkowita może być określonym zestawem 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. |, &, ^ itd.), możesz zdefiniować adnotację za pomocą atrybutu flag, aby sprawdzić, czy parametr lub wartość zwracana odwołują się do prawidłowego wzorca.

Podany niżej 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, jeśli parametr ozdobiony lub zwracana nie odnosi się do prawidłowego wzorca, generowane jest ostrzeżenie.

Zachowaj adnotację

Adnotacja @Keep zapewnia, że klasa lub metoda z adnotacjami nie są usuwane, gdy kod zostanie zmniejszony w czasie kompilacji. Adnotacja jest zwykle dodawana do metod i klas, do których dostęp jest uzyskiwany przez odbicie, aby kompilator nie uznawał kodu za nieużywany.

Uwaga: klasy i metody, do których dodajesz adnotacje za pomocą metody @Keep, zawsze znajdują się w pliku APK, nawet jeśli nigdy nie odwołujesz się do tych klas i metod w ramach jej logiki.

Jeśli chcesz utrzymać mały rozmiar aplikacji, zastanów się, czy konieczne jest zachowanie w niej wszystkich adnotacji @Keep. Jeśli korzystasz z odbicia, aby uzyskać dostęp do klasy lub metody z adnotacjami, użyj w regułach ProGuard warunków warunkowych -if, podając klasę wywołującą odczucia.

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

Adnotacje widoczności kodu

Za pomocą poniższych adnotacji możesz określić widoczność określonych części kodu, takich jak metody, klasy, pola czy pakiety.

Pokazuj kod na potrzeby testowania

Adnotacja @VisibleForTesting wskazuje, że metoda z adnotacjami 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 potrzeba udostępnienia jej na potrzeby testów. Lint używa argumentu otherwise, aby wymusić zamierzoną widoczność.

W tym przykładzie myMethod() to zwykle private, ale w testach – package-private. Oznaczenie VisibleForTesting.PRIVATE oznacza, że lint wyświetla komunikat, jeśli ta metoda została wywołana spoza kontekstu, na który zezwala dostęp private, na przykład z innej jednostki kompilacji.

Kotlin

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun myMethod() {
    ...
}

Java

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
void myMethod() { ... }

Możesz też podać wartość @VisibleForTesting(otherwise = VisibleForTesting.NONE), aby wskazać, że dana metoda istnieje tylko na potrzeby testowania. Ten formularz jest taki sam jak użycie @RestrictTo(TESTS). Obie funkcje wykonujeją tę samą kontrolę lintowania.

Ograniczanie interfejsu API

Adnotacja @RestrictTo wskazuje, że dostęp do interfejsu API (pakiet, klasa lub metoda) z adnotacjami jest ograniczony w ten 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ą klasę z adnotacjami. Modyfikator protected w Javie nie jest wystarczająco restrykcyjny, ponieważ umożliwia dostęp z niepowiązanych klas w tym samym pakiecie. Zdarzają się też sytuacje, w których zechcesz zostawić metodę public, aby zachować elastyczność w przyszłości, ponieważ nigdy nie możesz utworzyć wcześniej protected ani zastąpionej metody public, a chcesz dać wskazówkę, że klasa jest przeznaczona do użycia w klasie lub tylko w jej podklasach.

Biblioteki

Aby ograniczyć dostęp API tylko do swoich 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 uporządkować kod według dowolnej hierarchii pakietów, ale także udostępnić go grupie powiązanych bibliotek. Ta opcja jest już dostępna w bibliotekach Jetpack, które mają dużo kodu implementacji nieprzeznaczonego do użytku zewnętrznego. Aby udostępnić tę opcję w różnych uzupełniających bibliotekach Jetpack, musisz mieć public.

Testowanie

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

Dostęp do interfejsu API z adnotacjami ma tylko kod testowy. Uniemożliwia to innym deweloperom korzystanie z interfejsów API, które zamierzasz wykorzystywać tylko do testów.