Блог :: Вчера, 8:18 pm
Одним из важнейших этапов разработки и сопровождения API является обеспечение надежной диагностики ошибок. Качественные и информативные ответы от сервера позволяют разработчикам быстро находить и устранять проблемы, улучшают удобство работы с сервисом и повышают доверие пользователей.
В статье рассмотрены лучшие практики и примеры диагностики ошибок через API, позволяющие эффективно решать возникающие проблемы.
Четкая структура ответа
Четко организованные ответы делают общение с клиентами простым и понятным. Например, ответ должен включать:
Пример ответа в формате JSON:
Подробные сообщения об ошибках
Помимо статуса ошибки, предоставляйте развернутое сообщение, объясняющее причину произошедшего. Например:
Использование HTTP-кодов
Правильное использование HTTP-кодов позволяет более точно охарактеризовать произошедшую ошибку. Например:
В статье рассмотрены лучшие практики и примеры диагностики ошибок через API, позволяющие эффективно решать возникающие проблемы.
Основные принципы эффективной диагностики ошибок
Четкая структура ответа
Четко организованные ответы делают общение с клиентами простым и понятным. Например, ответ должен включать:
- Статус операции (
status); - Информационное сообщение (
message); - При необходимости — дополнительные данные (
data).
Пример ответа в формате JSON:
ВыделитьJSON
{
"status": "error",
"message": "Пользователь с таким email уже зарегистрирован.",
"data": {}
}Подробные сообщения об ошибках
Помимо статуса ошибки, предоставляйте развернутое сообщение, объясняющее причину произошедшего. Например:
ВыделитьPHP
header('Content-Type: application/json');
echo json_encode([
'status' => 'error',
'message' => 'Ошибка базы данных: '.$stmt->error
]);Использование HTTP-кодов
Правильное использование HTTP-кодов позволяет более точно охарактеризовать произошедшую ошибку. Например:
- 400 (Bad Request) — если данные переданы неверно;
- 401 (Unauthorized) — если пользователь не прошел авторизацию;
- 404 (Not Found) — если ресурс не найден;
- 500 (Internal Server Error) — если произошла внутренняя ошибка
- Жалоба
Блог :: 14.02.2026 09:45:19 am
Аннотация
1. Создание пользовательского интерфейса
Если функция должна выводить что-то на экран, она должна быть помечена аннотацией:
2. Вложенные композиционные функции
Если функция вызывает другие композиционные функции, она также должна быть помечена аннотацией
3. Функции, которые изменяют состояние
Если функция изменяет состояние (например, с помощью
Простой текст:
Кнопка с текстом:
Сложный интерфейс:
...
@Composable в Jetpack Compose используется для обозначения функций, которые могут создавать и обновлять пользовательский интерфейс. Эти функции называются композиционными функциями и могут содержать код, который описывает, как должен выглядеть пользовательский интерфейс.Когда использовать @Composable
1. Создание пользовательского интерфейса
Если функция должна выводить что-то на экран, она должна быть помечена аннотацией:
@Composable:
ВыделитьKotlin
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}2. Вложенные композиционные функции
Если функция вызывает другие композиционные функции, она также должна быть помечена аннотацией
@Composable:
ВыделитьKotlin
@Composable
fun Content() {
Greeting(name = "Kotlin")
}3. Функции, которые изменяют состояние
Если функция изменяет состояние (например, с помощью
remember), она должна быть помечена аннотацией @Composable:
ВыделитьKotlin
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Count: $count")
}
}Примеры
Простой текст:
ВыделитьKotlin
@Composable
fun SimpleText() {
Text("Hello, Compose!")
}Кнопка с текстом:
ВыделитьKotlin
@Composable
fun ButtonWithText() {
Button(onClick = { /* Обработка клика */ }) {
Text("Click me!")
}
}Сложный интерфейс:
ВыделитьKotlin
@Composable
fun ComplexUI() {
Column {
Text("Title")
Button(onClick = { /* Обработка клика */ }) {
Блог :: 14.02.2026 06:29:03 am
Врера, потребовалось воспользоваться
Чтобы решить, вместо этого:
Я использовал это:
Это безотказный вариант. Сегодня я попробовал вставить:
И всё было определенно.
Возможно потребуется импорт:
BuildConfig.VERSION_NAME для получения версии приложения, но она отказалась быть определённой.Чтобы решить, вместо этого:
ВыделитьKotlin
val versionApp = BuildConfig.VERSION_NAMEЯ использовал это:
Выделитьkotlin
val versionApp = try {
context.packageManager.getPackageInfo(context.packageName, 0).versionName
} catch (_: Exception) {
null
}Это безотказный вариант. Сегодня я попробовал вставить:
ВыделитьKotlin
val versionApp = BuildConfig.VERSION_NAMEИ всё было определенно.
Возможно потребуется импорт:
ВыделитьKotlin
import net.danfa.rush.BuildConfig
Блог :: 12.02.2026 01:59:35 pm
Корутины (coroutines) — это механизм в Kotlin, который позволяет писать асинхронный и неблокирующий код в стиле синхронного программирования. Корутины упрощают работу с асинхронными задачами, такими как сетевые запросы, работа с базами данных и другие длительные операции, без необходимости использования сложных конструкций, таких как коллбэки или потоки.
Асинхронность: Корутины позволяют выполнять длительные операции асинхронно, не блокируя основной поток.
Неблокирующий код: Корутины могут приостанавливаться и возобновляться без блокировки потока, что делает их эффективными для выполнения длительных операций.
Легкость в использовании: Корутины позволяют писать асинхронный код в стиле синхронного программирования, что упрощает чтение и понимание кода.
Пример использования корутин
Coroutine scope: Область видимости корутины, которая управляет её жизненным циклом. Например,
Suspend функции: Функции, которые могут приостанавливаться и возобновляться без блокировки потока. Они помечаются ключевым словом
Coroutine builder: Функции, которые запускают корутины. Например,
Корутины — это...
Основные особенности корутин
Асинхронность: Корутины позволяют выполнять длительные операции асинхронно, не блокируя основной поток.
Неблокирующий код: Корутины могут приостанавливаться и возобновляться без блокировки потока, что делает их эффективными для выполнения длительных операций.
Легкость в использовании: Корутины позволяют писать асинхронный код в стиле синхронного программирования, что упрощает чтение и понимание кода.
Пример использования корутин
ВыделитьKotlin
import kotlinx.coroutines.*
fun main() = runBlocking {
println("Start")
// Запуск корутины
launch {
delay(2000) // Приостановка корутины на 2 секунды
println("Coroutine executed after 2 seconds")
}
println("End")
}Основные компоненты корутин
Coroutine scope: Область видимости корутины, которая управляет её жизненным циклом. Например,
runBlocking, lifecycleScope, viewModelScope.Suspend функции: Функции, которые могут приостанавливаться и возобновляться без блокировки потока. Они помечаются ключевым словом
suspend.Coroutine builder: Функции, которые запускают корутины. Например,
launch, async.Заключение
Корутины — это...
Блог :: 12.02.2026 12:19:42 pm
Для примера возьмём список чатов и один чат, к которому будем писать код, чтобы перейти.
Для реализации перехода между списком чатов и конкретным чатом в Kotlin/Android, можно использовать следующий подход:
Список чатов (ChatListActivity/Fragment):
Activity/Fragment чата (ChatActivity):
В "layout" файле "activity_chat.xml" добавьте необходимые элементы для отображения чата (
Для реализации перехода между списком чатов и конкретным чатом в Kotlin/Android, можно использовать следующий подход:
Список чатов (ChatListActivity/Fragment):
ВыделитьKotlin
// При клике на элемент списка
chatList.setOnItemClickListener { parent, view, position, id ->
val chatId = chatList[position].id // Получаем id чата
// Создаем Intent для перехода
val intent = Intent(this, ChatActivity::class.java)
intent.putExtra("chat_id", chatId) // Передаем id чата
startActivity(intent)
}Activity/Fragment чата (ChatActivity):
ВыделитьKotlin
class ChatActivity : AppCompatActivity() {
private var chatId: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat)
// Получаем переданный id чата
chatId = intent.getIntExtra("chat_id", 0)
// Теперь можно использовать chatId для загрузки данных конкретного чата
loadChatData(chatId)
}
private fun loadChatData(id: Int) {
// Здесь логика загрузки сообщений для конкретного чата
// Например:
// val messages = database.getMessagesForChat(id)
}
}В "layout" файле "activity_chat.xml" добавьте необходимые элементы для отображения чата (
RecyclerView для сообщений, EditText для ввода и т.д.).Важные моменты
- Убедитесь, что ChatActivity добавлен в
Блог :: 12.02.2026 11:46:40 am
Метод setOnItemClickListener используется для установки обработчика кликов на элементы списка (например, в
В
...
ListView или RecyclerView). Этот метод позволяет вам реагировать на события, когда пользователь нажимает на элемент списка.Пример использования setOnItemClickListener в ListView
ВыделитьKotlin
val listView = findViewById<ListView>(R.id.list_view)
// Устанавливаем адаптер для ListView
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, arrayOf("Item 1", "Item 2", "Item 3"))
listView.adapter = adapter
// Устанавливаем обработчик кликов
listView.setOnItemClickListener { parent, view, position, id ->
// Здесь вы можете обработать клик на элемент списка
val clickedItem = parent.getItemAtPosition(position) as String
Toast.makeText(this, "Clicked: $clickedItem", Toast.LENGTH_SHORT).show()
}Пример использования setOnItemClickListener в RecyclerView
В
RecyclerView используется RecyclerView.Adapter, и вы можете установить обработчик кликов в методе onCreateViewHolder или onBindViewHolder.
ВыделитьKotlin
class MyAdapter(private val items: List<String>) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textView: TextView = itemView.findViewById(R.id.text_view)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
Блог :: 12.02.2026 07:15:44 am
Исключения являются важной частью программирования, поскольку позволяют обрабатывать непредвиденные ситуации и предотвращают крах приложения. В Kotlin существует специальный синтаксис для обработки исключений, аналогичный Java, однако имеются некоторые особенности и рекомендации по эффективному использованию конструкций
Конструкция try-catch позволяет перехватывать исключения, возникающие в процессе выполнения программы. Рассмотрим базовую структуру:
В качестве параметра блока
Пример:
Список основных видов исключений:
try-catch-finally.Основы конструкции try-catch
Конструкция try-catch позволяет перехватывать исключения, возникающие в процессе выполнения программы. Рассмотрим базовую структуру:
ВыделитьKotlin
try {
// код, потенциально способный вызывать исключение
} catch (e: ExceptionType) {
// обработчик конкретного типа исключения
}Параметры блока catch
В качестве параметра блока
catch указывается тип исключения (ExceptionType), которое мы хотим обработать. Это может быть класс конкретной ошибки либо общий родительский класс всех возможных ошибок (например, Throwable, Exception).Пример:
ВыделитьKotlin
try {
val result = divideNumbers(a, b)
} catch (e: ArithmeticException) {
println("Ошибка деления!")
}Список основных видов исключений:
- ArithmeticException — исключение, возникающее при попытке выполнить некорректную арифметическую операцию (например, деление на ноль).
- NullPointerException — выбрасывается, когда пытаешься вызвать метод или обращаться к полю объекта, равного
null. - ArrayIndexOutOfBoundsException — выдаётся, если обращаешься к элементу массива по индексу, выходящему за его границы.
- IllegalArgumentException — вызвано передачей метода
Блог :: 11.02.2026 06:32:49 am
В Kotlin для вывода кратковременных уведомлений (на 2–5 секунд) используется класс
Параметры:
Простой пример:
Расширенный пример (С настройкой позиции):
Toast из Android SDK.Основная функция‑конструктор
ВыделитьKotlin
Toast.makeText(context, text, duration).show()Параметры:
context— контекст приложения (например,thisвActivity,requireContext()во фрагменте).text— текст сообщения (строка или ресурсR.string.xxx).duration— длительность показа:Toast.LENGTH_SHORT— ~2 секунды;Toast.LENGTH_LONG— ~3,5 секунды.
Простой пример:
ВыделитьKotlin
Toast.makeText(this, "Операция выполнена!", Toast.LENGTH_SHORT).show()Расширенный пример (С настройкой позиции):
ВыделитьKotlin
val toast = Toast.makeText(this, "Сообщение с настройкой", Toast.LENGTH_LONG)
toast.setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL, 0, 50)
toast.show()setGravity(gravity, xOffset, yOffset) задаёт:
- позицию на экране (
Gravity.TOP,Gravity.CENTER,Gravity.BOTTOMи т. п.); - смещение по осям X и Y (в пикселях).
Важные нюансы
- Вызов
.show()обязателен — без негоToastне отобразится. - Контекст должен быть валидным (например, активность не должна быть уничтожена).
- Потокобезопасность —
Toastнужно вызывать из UI‑потока (в корутинах используйтеwithContext(Dispatchers.Main)). - Ограничения Android 12+:
- максимум 2 строки текста;
- система может объединять несколько Toast в одно уведомление.
Альтернативы (Когда Toast не подходит)
- Snackbar — если нужно добавить кнопку действия (например, «Отменить»).
- Dialog — если требуется подтверждение от пользователя.
- Notification — если сообщение должно
Блог :: 09.02.2026 05:47:14 pm
В Kotlin есть похожий функционал через метод replace с лямбда-выражением.
Вы можете использовать такую форму метода replace:
Это работает аналогично
Пример с регулярным выражением:
В лямбда-выражении доступны:
Это позволяет гибко обрабатывать замены с использованием регулярных выражений.
Вы можете использовать такую форму метода replace:
Выделитьkotlin
val text = "Исходный текст"
val regex = """шаблон""".toRegex()
// Пример использования
val result = text.replace(regex) { match ->
// Здесь можно обработать совпадение
// match.value содержит найденное значение
// Возвращаем новую строку для замены
"новая строка"
}
Это работает аналогично
preg_replace_callback в PHP. Вы можете:
- Получать доступ к найденным совпадениям.
- Обрабатывать их в лямбда-выражении.
- Возвращать новую строку для замены.
Пример с регулярным выражением:
Выделитьkotlin
val text = "123-456-789"
val regex = """(\d{3})""".toRegex()
val result = text.replace(regex) { match ->
"[$match.value]" // Обернем каждую группу цифр в квадратные скобки
}
// Результат будет: [123]-[456]-[789]
В лямбда-выражении доступны:
match.value- полное совпадение.match.groups- группы захвата.match.range- диапазон совпадения в строке.
Это позволяет гибко обрабатывать замены с использованием регулярных выражений.
Опрос :: 08.02.2026 08:53:01 am
Допустим для собственного приложения необходимо где-то хранить данные. Что лучше подходит, Firebase или свой сервер?
Статистика доступна после голосования Публичный опрос
Dopamine 09.02.2026 09:05:37 am
Работая над приложением размышлял, что использовать, выбрал Firebase и написал универсальный класс для работы с текстовыми сообщениями чатов, а так вспомогательные классы.
Когда протестировал свой код и убедился, что всё работает, вдруг передумал и стал писать классы для обработки данных с моим сервером (Api и необходимые "вспомогашки").
Мой выбор: Хранение данных - на своём сервере.
Firebase: Для Push-уведомлений.
Когда протестировал свой код и убедился, что всё работает, вдруг передумал и стал писать классы для обработки данных с моим сервером (Api и необходимые "вспомогашки").
Мой выбор: Хранение данных - на своём сервере.
Firebase: Для Push-уведомлений.
Блог :: 07.02.2026 07:13:40 am
Интеграция Firebase в Android-проект на Kotlin проста и понятна. Ниже приведён подробный пошаговый гайд, как подключить Firebase в ваше приложение.
Зарегистрируй проект в Firebase Console
Добавь проект Android в Firebase
Подготовь проект к работе с Firebase
Добавь
В файле верхнего уровня (project: build.gradle):
В файле уровня модуля (module: build.gradle):
Синхронизируй проект
После добавления указанных зависимостей, нажми кнопку "Sync Now" (Синхронизировать проект) в Android Studio.
Используй Firebase в своём коде
Чтобы начать пользоваться возможностями Firebase, создай...
Шаги подключения Firebase
Зарегистрируй проект в Firebase Console
- Перейдите на сайт Firebase Console: https://console.firebase.google.com/.
- Нажмите на кнопку "Add project" ("Добавить проект").
- Выберите название проекта и страну, нажмите "Continue".
- Включите отслеживание аналитики (Analytics) по желанию и завершите регистрацию проекта.
Добавь проект Android в Firebase
- На странице своего проекта выберите вкладку "Project Overview" и нажмите "Add app" ("Добавить приложение").
- Укажите пакетное имя вашего Android-приложения (например, `com.example.myapp`) и введите произвольное прозвище приложения.
- Скачай файл "google-services.json" и размести его в папке "app" вашего проекта.
Подготовь проект к работе с Firebase
Добавь
google.gms.google-services в файлы "build.gradle":В файле верхнего уровня (project: build.gradle):
ВыделитьGroovy
plugins {
id ("com.android.application") version '8.1.1' apply false
id ("com.google.gms.google-services") version '4.4.0' apply false
}В файле уровня модуля (module: build.gradle):
ВыделитьGroovy
plugins {
id ("com.android.application")
id ("com.google.gms.google-services")
}Синхронизируй проект
После добавления указанных зависимостей, нажми кнопку "Sync Now" (Синхронизировать проект) в Android Studio.
Используй Firebase в своём коде
Чтобы начать пользоваться возможностями Firebase, создай...
Блог :: 06.02.2026 11:14:44 am
Для замены названия темы, например,
Основной файл темы
Измените название функции в файле, где определена тема:
Файлы использования темы
Найдите все места, где используется текущая тема:
Файлы стилей и компонентов
Проверьте все файлы, где могут быть ссылки на тему:
Импорты и зависимости
Если тема находится в отдельном модуле, проверьте импорты:
Рекомендуется использовать функцию массовой замены в вашей IDE (например, Refactor → Rename в Android Studio), чтобы автоматически найти и обновить все упоминания. Не забудьте после изменений выполнить тестирование приложения, чтобы убедиться в корректной работе.
DANFATheme на RUSHTheme в Kotlin-проекте вам потребуется внести изменения в следующих местах:Основной файл темы
Измените название функции в файле, где определена тема:
ВыделитьKotlin
@Composable
fun DANFATheme(...) { ... } // заменить на
@Composable
fun RUSHTheme(...) { ... }Файлы использования темы
Найдите все места, где используется текущая тема:
ВыделитьKotlin
DANFATheme { ... } // заменить на
RUSHTheme { ... }Файлы стилей и компонентов
Проверьте все файлы, где могут быть ссылки на тему:
- В composable-компонентах.
- В theme.kt.
- В style.kt.
Импорты и зависимости
Если тема находится в отдельном модуле, проверьте импорты:
ВыделитьKotlin
import package.DANFATheme // заменить на
import package.RUSHThemeРекомендуется использовать функцию массовой замены в вашей IDE (например, Refactor → Rename в Android Studio), чтобы автоматически найти и обновить все упоминания. Не забудьте после изменений выполнить тестирование приложения, чтобы убедиться в корректной работе.
Блог :: 04.02.2026 07:15:08 am
Типы данных определяют, каким образом хранятся и обрабатываются данные в программе. В Kotlin, как и в большинстве статически типизированных языков, тип переменной определяется при её объявлении и влияет на операции, которые можно с ней производить.
Числовые типы
Строковый тип
Булевый тип
Специальные типы для Android
В Android-разработке часто приходится работать с текстом, который нуждается в дополнительном форматировании. Для этого используются специализированные типы данных:
Пример использования
...
Основные типы данных в Kotlin
Числовые типы
Int: целое число (32-bit).Long: длинное целое число (64-bit).Float: вещественное число одинарной точности (32-bit).Double: вещественное число двойной точности (64-bit).
Строковый тип
String: обычная строка текста.
Булевый тип
Boolean: логическое значение (trueилиfalse).
Специальные типы для Android
CharSequence: интерфейс, представляющий последовательность символов (часто используется в Android для работы с текстом).SpannableString: класс, который позволяет добавлять стили и разметку к текстовым данным (используется для форматирования текста в Android).
SpannableString и CharSequence
В Android-разработке часто приходится работать с текстом, который нуждается в дополнительном форматировании. Для этого используются специализированные типы данных:
CharSequence: представляет собой последовательность символов, которая может быть представлена как строка или спани.SpannableString: это подкласс CharSequence, который позволяет добавлять стили и разметку к тексту, например, менять цвет, шрифт, фон и т.п.
Пример использования
SpannableString:
Выделитьkotlin
val text = SpannableString("Hello, Android!")
text.setSpan(ForegroundColorSpan(Color.RED), 0, 5,
Блог :: 03.02.2026 09:38:54 am
В Kotlin/Android есть несколько способов организовать централизованное хранение конфигурационных переменных.
Создайте файл в "res/values/strings.xml":
Доступ через:
Создайте файл "Config.kt":
Доступ:
Настройте в "build.Gradle":
Доступ:
Создайте в "Application":
Доступ:
Ресурсные файлы (values)
Создайте файл в "res/values/strings.xml":
ВыделитьKotlin
<resources>
<string name="api_url">https://api.example.com</string>
<integer name="timeout">30000</integer>
<bool name="debug_mode">true</bool>
</resources>Доступ через:
R.string.api_url.Константы в отдельном файле
Создайте файл "Config.kt":
ВыделитьKotlin
object Config {
const val API_URL = "https://api.example.com"
const val TIMEOUT = 30000
const val DEBUG_MODE = true
}Доступ:
Config.API_URL.BuildConfig
Настройте в "build.Gradle":
ВыделитьGradle
buildTypes {
debug {
buildConfigField "String", "API_URL", "\"https://api.example.com\""
}
release {
buildConfigField "String", "API_URL", "\"https://api.prod.com\""
}
}Доступ:
BuildConfig.API_URL.Application-класс
Создайте в "Application":
ВыделитьKotlin
class MyApp: Application() {
companion object {
lateinit var API_URL: String
}
override fun onCreate() {
super.onCreate()
API_URL = "https://api.example.com"
}
}Доступ:
MyApp.API_URL.Environment Variables
- Для серверной разработки.
- Хранятся в
.envфайле. - Используются через библиотеки типа "kotlin-dotenv".
Рекомендации по выбору
- Для простых строковых констант — "strings.XML".
- Для глобальных констант приложения — "Config.kt".
- Для разных окружений — "BuildConfig".
- Для сложных
Блог :: 03.02.2026 07:10:14 am
Функции: Основы
Функция — это блок кода, который выполняет определённое действие и может быть вызван многократно.
Синтаксис:
ВыделитьKotlin
fun имяФункции(параметры): ТипВозврата {
// тело функции
return результат
}Пример простой функции:
ВыделитьKotlin
fun addNumbers(a: Int, b: Int): Int {
return a + b
}
// Вызов
val sum = addNumbers(5, 3) // sum = 8Важные моменты:
fun— ключевое слово для объявления функции.- Типы параметров и возвращаемого значения указываются явно.
- Если функция не возвращает значение, тип возврата —
Unit(можно не указывать).
Функции без возвращаемого значения
Когда функция выполняет действие, но не возвращает результат:
ВыделитьKotlin
fun showMessage(message: String) {
println(message)
}
// Вызов
showMessage("Привет из функции!")Значения параметров по умолчанию
Можно задать значения по умолчанию, чтобы не указывать их при вызове:
Выделитьkotlin
fun greet(name: String = "Гость") {
println("Привет, $name!")
}
// Варианты вызова:
greet() // "Привет, Гость!"
greet("Юля") // "Привет, Юля!"Именованные аргументы
При вызове можно явно указывать имена параметров:
Выделитьkotlin
fun createUser(name: String, age: Int, isActive: Boolean) {
println("$name, $age лет, активен: $isActive")
}
// Вызов с именованными аргументами
createUser(name = "Маша", age = 25, isActive = true)Лямбда‑выражения
Лямбда — это анонимная функция, которую можно передать как параметр.
Синтаксис:
ВыделитьKotlin
{ параметры ->
Блоги
Одним из важнейших этапов разработки и сопровождения API является обеспечение надежной диагностики ошибок. Качественные и информативные ответы от...
Аннотация @Composable в Jetpack Compose используется для обозначения функций, которые могут создавать и обновлять пользовательский интерфейс. Эти...
Kotlin: Конфигурация BuildConfig недоступна в файлах приложения
Врера, потребовалось воспользоваться BuildConfig.VERSION_NAME для получения версии приложения, но она отказалась быть определённой. Чтобы решить,...
Темы
6 ответов
6 ответов
1 ответ
3 ответа
Ссылки
Web Мастерская
Сообщество Web Мастеров. Тут собрано всё, чтобы написать свой первый сайт,...
Реклама






