Улучшите проверку кода с помощью аннотаций

Использование инструментов проверки кода, таких как lint , может помочь вам найти проблемы и улучшить ваш код, но эти инструменты способны дать лишь ограниченную информацию. Например, идентификаторы ресурсов Android используют int для идентификации строк, графики, цветов и других типов ресурсов, поэтому инструменты проверки не могут определить, когда вы указали строковый ресурс там, где следовало указать цвет. В результате ваше приложение может отображаться некорректно или вообще не запускаться, даже если вы используете проверку кода.

Аннотации позволяют предоставлять подсказки инструментам проверки кода, таким как lint, для обнаружения более тонких проблем в коде. Аннотации добавляются в виде метатегов, которые вы прикрепляете к переменным, параметрам и возвращаемым значениям для проверки возвращаемых значений методов, передаваемых параметров, локальных переменных и полей. При использовании с инструментами проверки кода аннотации могут помочь обнаружить такие проблемы, как исключения NullPointerException и конфликты типов ресурсов.

Android поддерживает различные аннотации через библиотеку Jetpack Annotations Library . Доступ к библиотеке можно получить через пакет androidx.annotation .

Примечание: Если модуль зависит от обработчика аннотаций, для добавления этой зависимости необходимо использовать конфигурацию зависимостей kapt или ksp для Kotlin или конфигурацию зависимостей annotationProcessor для Java.

Добавьте аннотации к своему проекту

Чтобы включить аннотации в вашем проекте, добавьте зависимость androidx.annotation:annotation в вашу библиотеку или приложение. Все добавленные вами аннотации будут проверяться при выполнении проверки кода или lint .

Добавьте зависимость от библиотеки Jetpack Annotations.

Библиотека Jetpack Anotations опубликована в репозитории Maven от Google . Чтобы добавить библиотеку Jetpack Anotations в свой проект, добавьте следующую строку в блок dependencies файла build.gradle или build.gradle.kts :

Котлин

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

Классный

dependencies {
    implementation 'androidx.annotation:annotation:1.9.1'
}
Затем на появившейся панели инструментов или в уведомлении о синхронизации нажмите «Синхронизировать сейчас» .

Если вы используете аннотации в собственном модуле библиотеки, они включаются в состав артефакта Android Archive (AAR) в формате XML в файле annotations.zip . Добавление зависимости androidx.annotation не создаёт зависимости для каких-либо последующих пользователей вашей библиотеки.

Примечание: Если вы используете другие библиотеки Jetpack, вам может не потребоваться добавлять зависимость androidx.annotation . Поскольку многие другие библиотеки Jetpack зависят от библиотеки Annotations, у вас, возможно, уже есть доступ к аннотациям.

Полный список аннотаций, включенных в репозиторий Jetpack, можно найти в справочнике по библиотеке аннотаций Jetpack или воспользоваться функцией автозаполнения, чтобы отобразить доступные параметры для оператора import androidx.annotation. .

Проверка выполнения кода

Чтобы запустить проверку кода в Android Studio, которая включает проверку аннотаций и автоматическую проверку синтаксиса, выберите в меню «Анализировать» > «Проверить код» . Android Studio отобразит сообщения о конфликтах, чтобы отметить потенциальные проблемы, где ваш код конфликтует с аннотациями, и предложить возможные решения.

Вы также можете принудительно устанавливать аннотации, запустив задачу lint из командной строки . Хотя это может быть полезно для выявления проблем с сервером непрерывной интеграции, задача lint не устанавливает аннотации на наличие значений null (описано в следующем разделе); это делает только Android Studio. Для получения дополнительной информации о включении и запуске проверок lint см. раздел «Улучшение кода с помощью проверок lint» .

Хотя конфликты аннотаций вызывают предупреждения, они не препятствуют компиляции вашего приложения.

Аннотации нулевой значимости

Аннотации проверки на null могут быть полезны в коде Java для обеспечения возможности присвоения значениям значения null. В коде Kotlin они менее полезны, поскольку в Kotlin существуют встроенные правила проверки на null, которые применяются на этапе компиляции.

Добавьте аннотации @Nullable и @NonNull для проверки того, является ли заданная переменная, параметр или возвращаемое значение нулевым. Аннотация @Nullable указывает на переменную, параметр или возвращаемое значение, которое может быть нулевым. Аннотация @NonNull указывает на переменную, параметр или возвращаемое значение, которое не может быть нулевым.

Например, если локальная переменная, содержащая значение null, передается в качестве параметра методу с аннотацией @NonNull , компиляция кода выдаст предупреждение о конфликте значений, не равных null. Кроме того, попытка обратиться к результату метода, помеченного аннотацией @Nullable , без предварительной проверки на null приводит к предупреждению о наличии значения null. Используйте аннотацию @Nullable для возвращаемого значения метода только в том случае, если каждое использование метода должно быть явно проверено на null.

Следующий пример демонстрирует возможность использования значений null. В примере кода на Kotlin аннотация @NonNull не используется, поскольку она автоматически добавляется в сгенерированный байт-код при указании типа, не допускающего значения null. В примере на Java аннотация @NonNull используется для параметров context и attrs , чтобы проверить, не являются ли переданные значения параметров нулевыми. Также проверяется, что сам метод onCreateView() не возвращает null:

Котлин

...
    /** 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) {
      ...
      }
...

Анализ нулёвости

Android Studio поддерживает анализ на наличие значений NULL для автоматического определения и вставки аннотаций, указывающих на их допустимость, в ваш код. Анализ на наличие значений NULL сканирует контракты во всей иерархии методов вашего кода для обнаружения:

  • Вызов методов, которые могут возвращать null.
  • Методы, которые не должны возвращать null.
  • Переменные, такие как поля, локальные переменные и параметры, могут иметь значение null.
  • Переменные, такие как поля, локальные переменные и параметры, которые не могут принимать значение null.

Затем в ходе анализа автоматически добавляются соответствующие нулевые аннотации в обнаруженные места.

Чтобы выполнить анализ на наличие значений NULL в Android Studio, выберите Analyze > Infer Nullity . Android Studio вставит аннотации Android @Nullable и @NonNull в обнаруженные места вашего кода. После выполнения анализа на наличие значений NULL рекомендуется проверить внедренные аннотации.

Примечание: При добавлении аннотаций проверки на null автозаполнение может предлагать аннотации IntelliJ @Nullable и @NotNull вместо аннотаций Android для проверки на null и может автоматически импортировать соответствующую библиотеку. Однако линт-проверщик Android Studio проверяет только аннотации Android для проверки на null. При проверке аннотаций убедитесь, что ваш проект использует аннотации Android для проверки на null, чтобы линт-проверщик мог корректно уведомить вас во время проверки кода.

Аннотации ресурсов

Проверка типов ресурсов может быть полезна, поскольку ссылки на ресурсы Android, такие как ресурсы drawable и string , передаются в виде целых чисел.

Код, который ожидает, что параметр будет ссылаться на ресурс определенного типа, например, String , может передаваться ожидаемому типу ссылки — int , но фактически ссылаться на ресурс другого типа, например, на ресурс типа R.string .

Например, добавьте аннотации @StringRes , чтобы проверить, содержит ли параметр ресурса ссылку на R.string , как показано здесь:

Котлин

abstract fun setTitle(@StringRes resId: Int)

Java

public abstract void setTitle(@StringRes int resId)

В процессе проверки кода аннотация генерирует предупреждение, если в параметре не указана ссылка R.string .

Аннотации для других типов ресурсов, таких как @DrawableRes , @DimenRes , @ColorRes и @InterpolatorRes , можно добавлять, используя тот же формат аннотаций, и запускать во время проверки кода.

Если ваш параметр поддерживает несколько типов ресурсов, вы можете добавить к @AnyRes аннотацию, указывающую на то, что аннотированный параметр может быть любым типом ресурса R

Хотя вы можете использовать аннотацию @ColorRes , чтобы указать, что параметр должен быть ресурсом цвета, целочисленный код цвета (в формате RRGGBB или AARRGGBB ) не распознается как ресурс цвета. Вместо этого используйте аннотацию @ColorInt , чтобы указать, что параметр должен быть целочисленным кодом цвета. Инструменты сборки будут отмечать некорректный код, который передает идентификатор ресурса цвета, например android.R.color.black , вместо целочисленного кода цвета, аннотированным методам.

Аннотации потока

Аннотации потоков проверяют, вызывается ли метод из потока определенного типа. Поддерживаются следующие аннотации потоков:

Инструменты сборки рассматривают аннотации @MainThread и @UiThread как взаимозаменяемые, поэтому вы можете вызывать методы @UiThread из методов @MainThread и наоборот. Однако в случае системных приложений с несколькими представлениями, работающими в разных потоках, поток пользовательского интерфейса может отличаться от основного потока. Поэтому следует аннотировать методы, связанные с иерархией представлений приложения, аннотацией @UiThread , а методы, связанные с жизненным циклом приложения, — аннотацией @MainThread .

Если все методы класса имеют одинаковые требования к многопоточности, вы можете добавить аннотацию одного потока к классу, чтобы убедиться, что все методы класса вызываются из одного и того же типа потока.

Одно из распространенных применений аннотаций потоков — проверка того, что методы или классы, аннотированные @WorkerThread , вызываются только из соответствующего фонового потока.

Аннотации ограничений значений

Используйте аннотации @IntRange , @FloatRange и @Size для проверки значений передаваемых параметров. Обе @IntRange и @FloatRange наиболее полезны при применении к параметрам, диапазон которых пользователи могут указать неправильно.

Аннотация @IntRange проверяет, находится ли значение параметра типа `int` или `long` в заданном диапазоне. В следующем примере показано, что параметр alpha должен содержать целое число от 0 до 255:

Котлин

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

Java

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

Аннотация @FloatRange проверяет, находится ли значение параметра типа `float` или `double` в заданном диапазоне значений с плавающей запятой. В следующем примере показано, что параметр alpha должен содержать значение типа `float` от 0,0 до 1,0:

Котлин

fun setAlpha(@FloatRange(from = 0.0, to = 1.0) alpha: Float) {...}

Java

public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {...}

Аннотация @Size проверяет размер коллекции или массива, а также длину строки. Аннотация @Size может использоваться для проверки следующих параметров:

  • Минимальный размер, например, @Size(min=2)
  • Максимальный размер, например, @Size(max=2)
  • Точный размер, например, @Size(2)
  • Число, размер которого должен быть кратным, например, @Size(multiple=2)

Например, @Size(min=1) проверяет, не пуста ли коллекция, а @Size(3) подтверждает, что массив содержит ровно три значения.

Следующий пример показывает, что массив location должен содержать как минимум один элемент:

Котлин

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);
}

Аннотации разрешений

Используйте аннотацию @RequiresPermission для проверки прав доступа вызывающего метода. Чтобы проверить наличие одного права доступа из списка допустимых, используйте атрибут anyOf . Чтобы проверить наличие набора прав доступа, используйте атрибут allOf . В следующем примере метод setWallpaper() аннотируется таким образом, чтобы указать, что вызывающий метод должен иметь permission.SET_WALLPAPERS permission.SET_WALLPAPERS:

Котлин

@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;

Для выполнения следующего примера требуется, чтобы вызывающий метод copyImageFile() имел как доступ на чтение к внешнему хранилищу, так и доступ на чтение к метаданным местоположения в скопированном изображении:

Котлин

@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) {
    //...
}

Для управления правами доступа к интентам укажите требование к правам доступа в строковом поле, определяющем имя действия интента:

Котлин

@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";

Для разрешений, которые требуются для доступа на чтение и запись у поставщиков контента, каждое требование к разрешению следует обернуть в аннотацию @RequiresPermission.Read или @RequiresPermission.Write :

Котлин

@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");

Косвенные разрешения

Если разрешение зависит от конкретного значения, переданного в параметр метода, используйте @RequiresPermission для самого параметра, не указывая конкретные разрешения. Например, метод startActivity(Intent) использует косвенное разрешение для намерения, переданного методу:

Котлин

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

Java

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

При использовании косвенных разрешений инструменты сборки выполняют анализ потока данных, чтобы проверить, содержит ли аргумент, передаваемый в метод, какие-либо аннотации @RequiresPermission . Затем они применяют все существующие аннотации из параметра к самому методу. В примере startActivity(Intent) аннотации в классе Intent вызывают предупреждения при некорректном использовании startActivity(Intent) когда в метод передается Intent без соответствующих разрешений, как показано на рисунке 1.

Рисунок 1. Предупреждение, сгенерированное аннотацией косвенных разрешений в методе startActivity(Intent) .

Инструменты сборки генерируют предупреждение в методе startActivity(Intent) на основе аннотации к соответствующему имени действия Intent в классе Intent :

Котлин

@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";

При необходимости вы можете заменить @RequiresPermission.Read @RequiresPermission @RequiresPermission.Write на @RequiresPermission при аннотировании параметра метода. Однако для косвенных разрешений @RequiresPermission не следует использовать совместно с аннотациями разрешений на чтение или запись.

Аннотации возвращаемого значения

Используйте аннотацию @CheckResult для проверки того, что результат или возвращаемое значение метода действительно используется. Вместо того чтобы аннотировать @CheckResult каждый метод, не являющийся `void`, добавьте аннотацию для уточнения результатов потенциально запутанных методов.

Например, начинающие Java-разработчики часто ошибочно полагают, что метод < String >.trim() удаляет пробелы из исходной строки. Аннотирование метода с помощью @CheckResult позволяет пометить случаи использования ` < String >.trim() , когда вызывающая сторона не вносит никаких изменений в возвращаемое значение метода.

В следующем примере метод checkPermissions() аннотируется для проверки того, действительно ли используется возвращаемое значение метода. Также в качестве альтернативного метода разработчику предлагается использовать enforcePermission() :

Котлин

@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);

Аннотации CallSuper

Используйте аннотацию @CallSuper , чтобы убедиться, что переопределяющий метод вызывает реализацию метода в родительском методе.

В следующем примере метод onCreate() снабжен аннотацией, гарантирующей, что любые переопределяющие методы будут вызывать super.onCreate() :

Котлин

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

Java

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

Типизированные аннотации

Аннотации TypeDef проверяют, ссылается ли конкретный параметр, возвращаемое значение или поле на определенный набор констант. Они также позволяют автозавершению кода автоматически предлагать допустимые константы.

Используйте аннотации @IntDef и @StringDef для создания перечисляемых аннотаций множеств целых чисел и строк, чтобы проверять другие типы ссылок на код.

Аннотации `typedef` используют @interface для объявления нового перечисляемого типа аннотации. Аннотации @IntDef и @StringDef , наряду с @Retention , аннотируют новую аннотацию и необходимы для определения перечисляемого типа. Аннотация @Retention(RetentionPolicy.SOURCE) указывает компилятору не сохранять данные перечисляемой аннотации в файле .class .

В следующем примере показаны шаги по созданию аннотации, которая проверяет, ссылается ли значение, переданное в качестве параметра метода, на одну из определенных констант:

Котлин

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);
}

При компиляции этого кода генерируется предупреждение, если параметр mode не ссылается на одну из определенных констант ( NAVIGATION_MODE_STANDARD , NAVIGATION_MODE_LIST или NAVIGATION_MODE_TABS ).

Объедините аннотации @IntDef и @IntRange чтобы указать, что целое число может представлять собой либо заданный набор констант, либо значение в заданном диапазоне.

Разрешить объединение констант с флагами

Если пользователи могут комбинировать разрешенные константы с флагом (например | , & , ^ и т. д.), вы можете определить аннотацию с атрибутом flag , чтобы проверить, ссылается ли параметр или возвращаемое значение на допустимый шаблон.

В следующем примере создается аннотация DisplayOptions со списком допустимых констант DISPLAY_ :

Котлин

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 {}

...

При компиляции кода с флагом аннотации генерируется предупреждение, если декорируемый параметр или возвращаемое значение не ссылаются на допустимый шаблон.

Сохранить аннотацию

Аннотация @Keep гарантирует, что аннотированный класс или метод не будет удален при минификации кода во время сборки. Эта аннотация обычно добавляется к методам и классам, к которым осуществляется доступ через рефлексию, чтобы предотвратить обработку компилятором кода как неиспользуемого.

Внимание: Классы и методы, помеченные аннотацией @Keep всегда отображаются в APK-файле вашего приложения, даже если вы никогда не ссылаетесь на эти классы и методы в логике приложения.

Чтобы уменьшить размер вашего приложения, подумайте, нужно ли сохранять каждую аннотацию @Keep в вашем приложении. Если вы используете рефлексию для доступа к аннотированному классу или методу, используйте условное выражение -if в ваших правилах ProGuard, указав класс, который выполняет вызовы рефлексии.

Для получения дополнительной информации о том, как минимизировать код и указать, какой код не следует удалять, см. раздел «Сжатие, обфускация и оптимизация вашего приложения» .

аннотации видимости кода

Используйте следующие аннотации для обозначения видимости определенных участков кода, таких как методы, классы, поля или пакеты.

Сделайте код доступным для тестирования.

Аннотация @VisibleForTesting указывает, что аннотированный метод имеет более высокую видимость, чем обычно необходимо для его тестирования. Эта аннотация имеет необязательный аргумент otherwise , который позволяет указать, какой была бы видимость метода, если бы не необходимость сделать его видимым для тестирования. Lint использует аргумент otherwise для обеспечения желаемой видимости.

В следующем примере myMethod() обычно является private , но для тестов он имеет package-private . При использовании обозначения VisibleForTesting.PRIVATE линт-код выводит сообщение, если этот метод вызывается вне контекста, разрешенного private доступом, например, из другого блока компиляции.

Котлин

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

Java

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

Вы также можете указать @VisibleForTesting(otherwise = VisibleForTesting.NONE) , чтобы обозначить метод как предназначенный только для тестирования. Этот вариант аналогичен использованию @RestrictTo(TESTS) . Оба варианта выполняют одну и ту же проверку линтера.

Ограничение доступа к API

Аннотация @RestrictTo указывает на то, что доступ к аннотированному API (пакету, классу или методу) ограничен следующим образом:

Подклассы

Используйте аннотацию вида @RestrictTo(RestrictTo.Scope.SUBCLASSES) , чтобы ограничить доступ к API только для подклассов.

Доступ к этому API имеют только классы, наследующие аннотированный класс. Модификатор protected в Java недостаточно ограничителен, поскольку он разрешает доступ из несвязанных классов в пределах одного пакета. Кроме того, бывают случаи, когда вы хотите оставить метод public для большей гибкости в будущем, поскольку вы никогда не сможете сделать ранее protected и переопределенный метод public , но хотите указать, что класс предназначен для использования только внутри класса или в его подклассах.

Библиотеки

Используйте аннотацию вида @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) , чтобы ограничить доступ к API только для ваших библиотек.

Доступ к аннотированному API имеет только код вашей библиотеки. Это позволяет не только организовать ваш код в любой желаемой иерархии пакетов, но и совместно использовать код с группой связанных библиотек. Эта опция уже доступна для библиотек Jetpack, содержащих большой объем кода, не предназначенного для внешнего использования, но который должен быть public для совместного использования различными дополнительными библиотеками Jetpack.

Тестирование

Используйте аннотацию @RestrictTo(RestrictTo.Scope.TESTS) , чтобы запретить другим разработчикам доступ к вашим тестовым API.

Доступ к аннотированному API имеют только тестовые примеры. Это предотвращает использование другими разработчиками API для разработки, если вы планируете использовать их исключительно в целях тестирования.