Kotlin | Вопросы собесов
2.57K subscribers
28 photos
966 links
Download Telegram
🤔 Как mutableState сообщает о том, что он изменился?

Каждый MutableState имеет подписчиков (observers), которые автоматически уведомляются об изменениях.
При обновлении значения, Compose отправляет сигнал о необходимости рекомпозиции тем элементам, которые используют это состояние.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
🤔 Как в interface оперировать со свойствами?

В interface можно определять свойства (val или var), но их реализация зависит от того, есть ли у них get и set.

🚩Свойства без реализации (только объявление)

В интерфейсе можно объявить val (только для чтения) или var (для чтения и записи), но без инициализации.
interface User {
val name: String // Объявляем свойство, но не реализуем
var age: Int // Может изменяться, но без начального значения
}


Использование в классе
class Person(override val name: String) : User {
override var age: Int = 25 // Обязательно реализовать
}


🚩Свойства с `get` (реализация в интерфейсе)

Можно задать кастомный геттер прямо в интерфейсе.
interface User {
val name: String
val greeting: String
get() = "Привет, $name!" // Реализация внутри интерфейса
}


Использование в классе
class Person(override val name: String) : User

fun main() {
val user = Person("Андрей")
println(user.greeting) // Привет, Андрей!
}


🚩Свойства с `get` и `set` (нельзя реализовать в интерфейсе)

Если в интерфейсе объявить var, то нельзя задать реализацию геттера и сеттера — их должен реализовать класс.
interface User {
var age: Int // Только объявление, без реализации
}


Использование в классе
class Person : User {
override var age: Int = 30 // Реализуем свойство
}


🚩Свойства с `get() = field` (не работает в интерфейсе!)

В interface нельзя использовать field (бэкинг-поле), потому что у интерфейсов нет состояния.
interface User {
var age: Int
get() = field // Ошибка! Нельзя использовать `field` в интерфейсе
set(value) { field = value }
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 Какой будет возвращаемый тип у suspend-функции, которая возвращает String, после компиляции?

Возвращаемый тип становится Any, потому что функция может вернуть либо String, либо корутину в приостановленном состоянии.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
🤔 Swich в котлине?

В Kotlin нет switch, но его заменяет более мощный оператор when.

Простой пример (аналог switch-case)
fun getDayName(day: Int): String {
return when (day) {
1 -> "Понедельник"
2 -> "Вторник"
3 -> "Среда"
4 -> "Четверг"
5 -> "Пятница"
6 -> "Суббота"
7 -> "Воскресенье"
else -> "Некорректный день"
}
}

fun main() {
println(getDayName(3)) // Среда
}


when без else (если учтены все случаи)
fun getStatus(code: Int): String = when (code) {
200 -> "OK"
404 -> "Not Found"
500 -> "Server Error"
}


Несколько значений в одном case
fun isWeekend(day: Int): Boolean {
return when (day) {
6, 7 -> true // Оба значения работают как один case
else -> false
}
}


🚩`when` как альтернатива `if-else`

Можно проверять логические выражения, а не просто числа.
fun checkNumber(x: Int): String {
return when {
x < 0 -> "Отрицательное число"
x == 0 -> "Ноль"
x > 0 -> "Положительное число"
else -> "Ошибка"
}
}


Использование when без аргумента
fun describe(obj: Any): String {
return when {
obj is String -> "Это строка"
obj is Int -> "Это число"
obj is Boolean -> "Это логический тип"
else -> "Неизвестный тип"
}
}


🚩`when` в качестве выражения

when можно использовать как выражение, возвращая результат:
val message = when (val code = 404) {
200 -> "OK"
404 -> "Not Found"
else -> "Unknown"
}
println(message) // Not Found


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🤯1👾1
🤔 Как создать suspend-функцию?

Создать suspend-функцию можно, добавив suspend перед fun.
suspend-функции нельзя вызывать напрямую из обычных функций, только из корутин.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🤯5😁3🔥1
🤔 С чем связаны ограничения на запуск сервисов?

Google постоянно ограничивает работу сервисов в Android, чтобы:
Уменьшить расход батареи
Оптимизировать использование памяти
Защитить пользователя от фоновых процессов, "убивающих" производительность

🟠Запрет на запуск сервисов в фоне (Android 8+)
Сервис нельзя запустить из фона, если приложение не активно.
startService(Intent) выдаст ошибку, если приложение не на переднем плане.
1. Использовать Foreground Service (с уведомлением).
2. Использовать JobIntentService / WorkManager.
class MyForegroundService : Service() {
override fun onCreate() {
super.onCreate()
val notification = NotificationCompat.Builder(this, "channelId")
.setContentTitle("Сервис работает")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.build()

startForeground(1, notification) // Запускаем сервис в Foreground
}

override fun onBind(intent: Intent?): IBinder? = null
}


🟠Запрет на старт сервисов из фона (Android 10+)
Если сервис запущен из фона (например, через BroadcastReceiver), он не запустится.
Исключение – если сервис работает в Foreground или с AlarmManager.
1. Использовать WorkManager (лучший вариант).
2. Использовать Foreground Service с уведомлением.
3. Использовать AlarmManager для периодических задач.

🟠Ограничение работы сервисов в спящем режиме (Doze Mode, Android 6+)
В спящем режиме (Doze Mode) система отключает сервисы.
Приложения не могут выполнять фоновые задачи.
Использовать Foreground Service.
Использовать JobScheduler / WorkManager.
Использовать Firebase Cloud Messaging (FCM) для пробуждения приложения.

🟠Запрет на работу сервисов после закрытия приложения (Android 9+)
Если пользователь смахнул приложение из списка недавних, фоновые сервисы будут убиты.
Решение → Foreground Service + startForeground() или JobScheduler.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🤔 Откуда можно запускать suspend-функции?

suspend-функции можно запускать только из корутин.
Можно вызывать их из:
1. launch {} или async {} в CoroutineScope
2. Другое suspend-функции`
3. runBlocking {} (для тестирования в main-потоке)


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🤯2🔥1😁1🤔1
🤔 Можно ли создать анонимный класс внутри inline функции?

Анонимный класс внутри inline-функции будет инстанцироваться при каждом вызове функции, что ломает цель inline — избавляться от накладных расходов на объекты.

🚩Что такое анонимный класс в Kotlin?

Анонимный класс — это класс без имени, который можно создать с помощью object : Interface {}.
interface ClickListener {
fun onClick()
}

fun main() {
val listener = object : ClickListener {
override fun onClick() {
println("Кнопка нажата!")
}
}

listener.onClick()
}


🚩Анонимный класс в `inline`-функции

Если мы создадим анонимный класс внутри inline-функции, он будет создаваться каждый раз при вызове функции!
inline fun setClickListener(action: () -> Unit) {
val listener = object : ClickListener {
override fun onClick() {
action()
}
}
listener.onClick()
}

fun main() {
setClickListener { println("Нажато!") }
}


Ошибка компиляции
Inline function cannot contain object expressions


🚩Как обойти ограничение?

Если нужно использовать inline, можно передавать лямбду вместо анонимного класса.
Рабочий вариант
inline fun setClickListener(noinline action: () -> Unit): ClickListener {
return object : ClickListener {
override fun onClick() {
action()
}
}
}

fun main() {
val listener = setClickListener { println("Нажато!") }
listener.onClick()
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Рекомпозиция происходит в рандомное время или по команде хореографера?

Рекомпозиция управляется Android Choreographer, который работает с VSYNC.
Процесс:
1. Изменение MutableState ставит флаг "UI требует перерисовки".
2. Choreographer ждет ближайший VSYNC и запускает рекомпозицию.
3. Перерисовываются только измененные элементы UI.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍2🤯1
🤔 Основные отличия Android 4 (Ice Cream Sandwich / Jelly Bean / KitKat) и Android 5 (Lollipop)

Android 5.0 Lollipop стал огромным обновлением по сравнению с Android 4.x, изменив интерфейс, архитектуру и производительность.

🟠Новый интерфейс — Material Design
Android 4: использовал Holo UI (чёрно-серый стиль с минимализмом).
Android 5: представил Material Design — новый визуальный стиль с тенями, анимациями и цветными кнопками.
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_add"
app:backgroundTint="@color/colorAccent"/>


🟠Новый движок ART вместо Dalvik
Android 4: использовал Dalvik (Just-in-Time, JIT) — код компилировался во время работы приложения.
Android 5: перешёл на ART (Ahead-of-Time, AOT) — код компилируется один раз при установке.

🟠Новый способ работы с уведомлениями
Android 4: уведомления были простыми и появлялись только в статус-баре.
Android 5: представил Heads-up Notifications (всплывающие уведомления).
val notification = NotificationCompat.Builder(context, "channel_id")
.setContentTitle("Новое сообщение")
.setContentText("Привет, как дела?")
.setPriority(NotificationCompat.PRIORITY_HIGH) // Heads-up уведомление
.setSmallIcon(R.drawable.ic_message)
.build()


🟠Поддержка 64-битных процессоров
Android 4: только 32-битная архитектура.
Android 5: появилась поддержка 64-битных процессоров, что улучшило производительность и работу с памятью.

🟠Улучшенное управление питанием — Project Volta
Android 4: не имел централизованного контроля за энергопотреблением.
Android 5: представил Project Volta, который продлевает жизнь батареи.
val jobScheduler = getSystemService(JobScheduler::class.java)
val jobInfo = JobInfo.Builder(1, ComponentName(this, MyJobService::class.java))
.setRequiresCharging(true) // Выполнить только при зарядке
.build()
jobScheduler.schedule(jobInfo)


🟠Новый режим многозадачности (Recent Apps)
Android 4: старые приложения в "Недавних" выглядели как список окон.
Android 5: приложения теперь отображаются в виде стопки карт (Card Stack UI).

🟠Улучшенная безопасность
Шифрование устройства включено по умолчанию (Android 5).
SELinux (Security-Enhanced Linux) теперь работает в принудительном (enforcing) режиме.
Добавлен Smart Lock → автоматическая разблокировка устройства по Bluetooth / Wi-Fi / лицу.

🟠Поддержка API для Wear OS и TV
Android 5 впервые добавил поддержку Android Wear (умные часы) и Android TV.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
😁3👍2
🤔 Как функция определяет, что она suspend'илась?

Suspend-функция не блокирует поток, а передает управление Continuation-объекту.
Функция "узнает" о приостановке через:
- Фрейм Continuation: если вызвана другая suspend-функция, текущая приостанавливает свое выполнение.
- Корутинный диспетчер: приостановка возможна, если выполнение ушло в другой поток (withContext).
- Возвращение специального маркера COROUTINE_SUSPENDED: сигнализирует Kotlin Runtime, что выполнение отложено.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5🤯3
🤔 Свойства какого вида можно добавить как расширение?

В Kotlin можно добавлять свойства-расширения (extension properties), но только с кастомным get (геттером).

🚩Можно добавлять `val` с `get()`

Расширяемые свойства могут быть только вычисляемыми (val), потому что нельзя создать field внутри расширения.
val String.firstChar: Char
get() = this[0]

fun main() {
println("Kotlin".firstChar) // K
}


🚩`var` работает только с `get()` и `set()`

Для var нужно и get(), и set(), но всё равно нельзя использовать field.
var StringBuilder.lastChar: Char
get() = this[length - 1]
set(value) {
this.setCharAt(length - 1, value)
}

fun main() {
val sb = StringBuilder("Hello")
println(sb.lastChar) // o

sb.lastChar = '!'
println(sb) // Hell!
}


🚩Нельзя создавать свойства с `field`

Такой код НЕ скомпилируется!
var String.someProperty: String = "Default" // Ошибка!


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Что известно про snapshot'ы?

Это механизм, позволяющий атомарно управлять состоянием.
Основные характеристики snapshot:
- Снимки (snapshots) позволяют фиксировать состояние в определенный момент времени.
- Внесенные изменения откладываются до момента коммита (commit).
- Работают аналогично транзакциям – можно откатить изменения, если они конфликтуют.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 Зачем нужны Data Class и Sealed Classes?

Data Class и Sealed Class решают разные задачи и обеспечивают улучшения в организации кода, управлении состоянием и безопасности типов. Они вносят значительные упрощения и повышают читаемость кода в Kotlin-проектах.

🚩Зачем они нужны

Data Class предназначены для хранения данных и автоматически предоставляют ряд полезных методов, что упрощает разработку и уменьшает объем шаблонного кода. Основные причины использования Data Class:

🟠Сокращение кода
Автоматически генерирует методы equals(), hashCode(), и toString(), а также copy() и компонентные функции для объектов данных. Это избавляет от необходимости ручной реализации этих методов, что уменьшает количество кода и возможность ошибок.

🟠Упрощение передачи данных
Идеально подходят для передачи данных между различными частями приложения, например, между слоями в архитектуре MVVM или при передаче данных между активностями и фрагментами.

🟠Поддержка неизменяемости
С помощью них легко создавать неизменяемые объекты, что способствует безопасной работе с данными, особенно в многопоточной среде.

🚩Зачем они нужны

Sealed Class используются для определения закрытых иерархий классов, где все потомки известны и ограничены. Они полезны по следующим причинам:

🟠Полное покрытие случаев в `when`
Гарантируют, что все возможные подтипы обработаны в выражениях when, что предотвращает ошибки во время выполнения из-за пропущенных случаев. Это упрощает управление состояниями и делает код более безопасным и предсказуемым.

🟠Ограниченное наследование
Ограничивают возможность создания подклассов за пределами файла, в котором они объявлены. Это предотвращает неожиданное наследование и сохраняет иерархию классов контролируемой и понятной.

🟠Инкапсуляция
Поскольку все расширения таких классов должны быть объявлены в том же файле, это способствует лучшей инкапсуляции и организации кода.

data class User(val name: String, val age: Int)


Пример Sealed Class
sealed class Result {
data class Success(val data: String) : Result()
data class Failure(val error: Throwable) : Result()
}

fun handleResult(result: Result) {
when (result) {
is Result.Success -> println("Success with data: ${result.data}")
is Result.Failure -> println("Failure with error: ${result.error.message}")
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 Как связаны VSYNC и события рекомпозиции?

Это механизм, который синхронизирует отрисовку UI с частотой обновления экрана.
- В Android VSYNC происходит 60 раз в секунду (или больше на устройствах с высокой герцовкой).
- Compose привязывает рекомпозицию к VSYNC, чтобы отрисовка происходила плавно и эффективно.
- Изменения состояния приводят к запросу рекомпозиции, но реальная перерисовка выполняется только при следующем VSYNC-событии.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
🤔 В чем различие Default диспатчер и IO диспатчер?

В Kotlin Coroutines есть несколько диспетчеров (Dispatchers), но Default и IO используются чаще всего.

🚩Главное различие:

Dispatchers.Default — для тяжёлых вычислений (CPU-операции).
Dispatchers.IO — для операций ввода-вывода (сеть, файлы, БД).

🟠`Dispatchers.Default` – для сложных вычислений (CPU-bound)
Этот диспетчер используется, если код загружает процессор (например, сложные вычисления).
import kotlinx.coroutines.*

fun main() = runBlocking {
launch(Dispatchers.Default) {
val result = heavyComputation()
println("Результат: $result")
}
}

suspend fun heavyComputation(): Int {
delay(1000)
return (1..1_000_000).sum()
}


🟠`Dispatchers.IO` – для работы с файлами, сетью, БД (IO-bound)
Этот диспетчер оптимизирован для ввода-вывода (I/O): работа с файлами, сетью, БД.
import kotlinx.coroutines.*
import java.io.File

fun main() = runBlocking {
launch(Dispatchers.IO) {
val text = File("data.txt").readText()
println("Файл прочитан: $text")
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Какие классы будут автоматически выводиться как stable?

Классы в Jetpack Compose автоматически считаются stable, если:
- Они data-классы.
- Они неизменяемые (immutable).
- Все их свойства состоят из stable типов (например, String, Int, Float).
- Они не используют ссылочные типы с изменяемым состоянием.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1🤔1
🤔 Зачем нужен DiffUtil?

DiffUtil — это утилита для быстрого обновления списков в RecyclerView. Она сравнивает старый и новый список и находит различия, чтобы обновлять только изменённые элементы, а не весь список.

🚩Проблема без `DiffUtil`

Обычное обновление списка без DiffUtil перерисовывает всё, даже если изменился один элемент.
adapter.notifyDataSetChanged() // Полностью обновляет список 


🟠Решение с `DiffUtil`
DiffUtil находит различия между старым и новым списком и обновляет только изменённые элементы.
class MyDiffUtilCallback(
private val oldList: List<User>,
private val newList: List<User>
) : DiffUtil.Callback() {

override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size

override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].id == newList[newItemPosition].id
}

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition] // Используем data class (авто `equals()`)
}
}


🚩Как использовать `DiffUtil` в `RecyclerView.Adapter`?

После создания DiffUtil.Callback, вызываем DiffUtil.calculateDiff() и передаём результат в adapter.
fun updateList(newList: List<User>) {
val diffCallback = MyDiffUtilCallback(userList, newList)
val diffResult = DiffUtil.calculateDiff(diffCallback)

userList = newList // Обновляем старый список
diffResult.dispatchUpdatesTo(this) // Обновляем только изменённые элементы
}


🟠`ListAdapter` – ещё проще!
Если используем ListAdapter, DiffUtil уже встроен.
class UserAdapter : ListAdapter<User, UserViewHolder>(DIFF_CALLBACK) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_user, parent, false)
return UserViewHolder(view)
}

override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bind(getItem(position)) // `getItem()` уже работает с `ListAdapter`
}

companion object {
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(oldItem: User, newItem: User): Boolean =
oldItem.id == newItem.id

override fun areContentsTheSame(oldItem: User, newItem: User): Boolean =
oldItem == newItem
}
}
}


Обновление списка в ListAdapter
adapter.submitList(newList) // DiffUtil работает внутри 🚀


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81🤔1
🤔 Как работают под капотом suspend-функции?

suspend-функции в Kotlin приостанавливают выполнение без блокировки потока.
Под капотом:
1. Suspend-функция разбивается на несколько частей (continuations).
2. Приостанавливается, если выполняется асинхронный код (например, delay(), withContext()).
3. Продолжается с места остановки, когда результат готов.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3🎉1
Forwarded from easyoffer
На easyoffer 2.0 появится:
🎯 Тренажер "Проработка вопросов"

Метод интервальных повторений и флеш-карточки
Персональный подход изучения на основе ваших ответов
Упор на самые частые вопросы

📌 Интервальные повторения по карточкам это научно доказанный метод эффективного обучения. Каждая карточка – это вопрос, который задают на собеседовании, вы можете выбрать "Не знаю", "Знаю", "Не спрашивать". После ответа вам показывается правильный ответ и возможность изучить вопрос подробнее (примеры ответов других людей). От ваших ответов зависит то, как часто карточки будут показываться на следующей тренировке. Трудные вопросы показываются чаще, простые – реже. Это позволяет бить в слабые места. Кроме того, изначальный порядок карточек зависит от частотности (вероятности встретить вопрос).

🚀 Благодаря этому тренажеру вы сможете очень быстро подготовиться к собеседованию, т.к. фокусируетесь отвечать на самые частые вопросы. Именно так готовился я сам, когда искал первую работу программистом.

Уже в течение недели я объявлю о старте краудфандинговой кампании на сбор финансирования, чтобы ускорить разработку сайта. Все кто поддержит проект до официального релиза получат самые выгодные условия пользования сервисом. А именно 1 год доступа к сайту по цене месячной подписки.

‼️ Очень важно, чтобы как можно больше людей поддержали проект в первые дни, по-этому те кто окажет поддержку первыми получат еще более выгодную стоимость на годовую подписку и существенный 💎 бонус о котором я позже расскажу в этом телеграм канале. Подписывайтесь, чтобы узнать о старте проекта раньше других и воспользоваться лимитированными вознаграждениями.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 В андроиде существуют мэпы, в которые можно положить примитивные типы?

Да! В Android есть специальные Map-коллекции, которые позволяют хранить примитивные типы (int, long, boolean и т. д.) без автоупаковки (autoboxing).

🚩Почему это важно?

Обычные HashMap<Int, Int> в Kotlin используют автоупаковку (Integer вместо int), что:
Увеличивает потребление памяти (из-за объектов Integer, Long и т. д.).
Замедляет работу (из-за ненужного создания объектов).

Решение? Использовать специализированные мэпы из android.util!

🚩`SparseArray` (замена `HashMap<Int, Any?>`)

Хранит пары Int → Any, но без автоупаковки.
import android.util.SparseArray

val sparseArray = SparseArray<String>()
sparseArray.put(1, "Привет")
sparseArray.put(2, "Мир")

println(sparseArray[1]) // Привет
println(sparseArray[2]) // Мир


🚩`SparseIntArray` (замена `HashMap<Int, Int>`)

Хранит пары Int → Int без автоупаковки.
import android.util.SparseIntArray

val sparseIntArray = SparseIntArray()
sparseIntArray.put(1, 100)
sparseIntArray.put(2, 200)

println(sparseIntArray[1]) // 100
println(sparseIntArray[2]) // 200


🚩`SparseBooleanArray` (замена `HashMap<Int, Boolean>`)

Оптимизирован для Int → Boolean пар.
import android.util.SparseBooleanArray

val sparseBooleanArray = SparseBooleanArray()
sparseBooleanArray.put(1, true)
sparseBooleanArray.put(2, false)

println(sparseBooleanArray[1]) // true
println(sparseBooleanArray[2]) // false


🚩`LongSparseArray<T>` (замена `HashMap<Long, T>`)

Оптимизирован для Long → Any?, аналог SparseArray, но с Long ключами.
import android.util.LongSparseArray

val longSparseArray = LongSparseArray<String>()
longSparseArray.put(10000000000L, "Длинный ключ")

println(longSparseArray[10000000000L]) // Длинный ключ


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8