Kotlin | Вопросы собесов
2.52K subscribers
28 photos
1.03K links
Download Telegram
🤔 Может ли потеря state быть связанной с фрагментом?

Да, потеря состояния (state) может быть связана с фрагментами (Fragments) в Android. Это довольно распространённая проблема, особенно при работе с динамическими интерфейсами. Давайте разберёмся, почему она возникает, как её предотвратить и какие решения существуют.

🚩Почему происходит потеря состояния во фрагментах?

🟠Жизненный цикл фрагмента
Фрагменты имеют сложный жизненный цикл, который тесно связан с активностью. Основные этапы:
onCreate() — создаётся фрагмент, инициализируются объекты.
onViewCreated() — создаётся View (UI компоненты).
onStart() / onResume() — фрагмент становится видимым и активным.
onPause() / onStop() — фрагмент приостанавливается.
onDestroyView() — уничтожается только View (UI), но сам фрагмент всё ещё существует.
onDestroy() — полностью уничтожается фрагмент.
Фрагменты могут пересоздаваться системой, например, при смене ориентации экрана или нехватке памяти. Если разработчик неправильно сохраняет состояние фрагмента, оно может быть утеряно.

🟠Удаление View фрагмента системой
Когда фрагмент переходит в состояние onDestroyView(), его View уничтожается, но сам объект фрагмента сохраняется. Если пользователь вернётся к этому фрагменту, View будет пересоздана, и вы потеряете все изменения, сделанные ранее, если они не сохранены явно.

🟠Проблемы с менеджером фрагментов
Использование FragmentManager или FragmentTransaction с неправильными методами, такими как replace() или add(), без должного управления стэком (back stack), может привести к пересозданию или дублированию фрагментов, что вызывает потерю состояния.

🟠Проблемы с `savedInstanceState`
Фрагменты, как и активности, используют механизм сохранения состояния через BundleonSaveInstanceState). Если состояние не сохранено правильно, данные могут быть потеряны.

🚩Как предотвратить потерю состояния во фрагментах?

🟠Сохранение данных в `onSaveInstanceState`
При уничтожении фрагмента система вызывает метод onSaveInstanceState(). Здесь вы можете сохранить важные данные в Bundle.
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("key_text", editText.text.toString())
}


При пересоздании фрагмента данные можно восстановить в onViewCreated()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val restoredText = savedInstanceState?.getString("key_text")
editText.setText(restoredText)
}


🟠Использование `ViewModel`
Для хранения состояния, которое переживает уничтожение и пересоздание фрагмента, лучше использовать архитектурный компонент ViewModel.
1⃣Создайте ViewModel
class MyViewModel : ViewModel() {
val textData = MutableLiveData<String>()
}


2⃣Используйте его во фрагменте
class MyFragment : Fragment() {
private lateinit var viewModel: MyViewModel

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)

// Восстановление данных
viewModel.textData.observe(viewLifecycleOwner) { text ->
editText.setText(text)
}

// Сохранение данных при изменении
editText.addTextChangedListener {
viewModel.textData.value = it.toString()
}
}
}


🟠Использование `FragmentManager` правильно
При работе с фрагментами всегда добавляйте их в back stack, если вы хотите сохранить состояние.
val fragment = MyFragment()
parentFragmentManager.beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit()


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

Через Gradle:
1. Компиляция исходников,
2. Обработка ресурсов,
3. Генерация R и BuildConfig,
4. Объединение в .apk или .aab,
5. Подпись и выравнивание.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
🤔 В чем различие 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
👍3
🤔 Почему необходимо использовать @Binds вместо @Provide?

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

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

В Android для наложения (перекрытия) элементов друг на друга используется FrameLayout или Box (в Jetpack Compose).

🚩FrameLayout (в XML и View)

FrameLayout — это контейнер, в котором все вложенные элементы располагаются в левом верхнем углу, но при этом могут накладываться друг на друга.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/background" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Наложенный текст"
android:textSize="24sp"
android:textColor="#FFFFFF"
android:layout_gravity="center"/>
</FrameLayout>


🚩Box (в Jetpack Compose)

В Jetpack Compose аналогом FrameLayout является Box. Он также позволяет располагать элементы друг над другом.
Box(
modifier = Modifier.fillMaxSize()
) {
Image(
painter = painterResource(id = R.drawable.background),
contentDescription = "Фон",
modifier = Modifier.fillMaxSize()
)

Text(
text = "Наложенный текст",
fontSize = 24.sp,
color = Color.White,
modifier = Modifier.align(Alignment.Center)
)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Как работает SOLID-принцип SRP?

Принцип единственной ответственности (Single Responsibility Principle) гласит, что класс должен иметь одну, и только одну, причину для изменения. Это означает:
1. Класс должен выполнять только одну задачу или отвечать за один аспект функциональности.
2. Изменения в одной части функционала не должны влиять на другие аспекты.
3. Это упрощает сопровождение, тестирование и повторное использование кода.


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

🟠Profile GPU Rendering
Этот инструмент показывает время, затраченное на отрисовку каждого кадра. Использование этого инструмента позволяет выявить "тяжелые" кадры и измерить улучшения после оптимизации.

1⃣Включите режим разработчика на устройстве.
2⃣Перейдите в "Настройки" -> "Для разработчиков".
3⃣Включите опцию "Profile GPU Rendering" и выберите "On screen as bars".
4⃣Запустите ваше приложение и наблюдайте за графиками. Зеленые линии указывают на время отрисовки, и ваша цель - оставаться ниже 16 мс (для 60 кадров в секунду).

🟠Android Profiler
Предоставляет набор инструментов для анализа производительности приложения.

1⃣ Откройте Android Studio и запустите ваше приложение.
2⃣Перейдите в "View" -> "Tool Windows" -> "Profiler".
3⃣Выберите ваше устройство и запущенное приложение.
4⃣Используйте вкладки CPU, Memory, Network и Energy для анализа различных аспектов производительности.
5⃣Сравните данные до и после оптимизации.

🟠Benchmarking
Создание и использование тестов производительности помогает количественно оценить улучшения. Вы можете использовать библиотеку Jetpack Benchmark для создания и выполнения тестов производительности.

🚩Пример использования Jetpack Benchmark:

1⃣Добавьте зависимости в build.gradle:
dependencies {
androidTestImplementation "androidx.benchmark:benchmark-junit4:1.1.0"
androidTestImplementation "androidx.test:runner:1.3.0"
androidTestImplementation "androidx.test:rules:1.3.0"
}


2⃣Создайте класс теста:
import androidx.benchmark.junit4.BenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class ExampleBenchmark {
@get:Rule
val benchmarkRule = BenchmarkRule()

@Test
fun myFunctionBenchmark() {
benchmarkRule.measureRepeated {
// Вызов вашей функции или кода для тестирования производительности
myFunction()
}
}
}


🟠Logcat
Используйте журналирование для измерения времени выполнения определенных операций.
val startTime = System.currentTimeMillis()
// Ваш код
val endTime = System.currentTimeMillis()
Log.d("Performance", "Время выполнения: ${endTime - startTime} мс")


🟠StrictMode
StrictMode помогает обнаружить операции, которые могут замедлить работу приложения, такие как работа с сетью или базой данных в главном потоке.
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
}


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

1⃣Включите режим разработчика на устройстве.
2⃣В "Настройки" -> "Для разработчиков" включите "Enable GPU Debug Layers".
3⃣Запустите команду adb shell am broadcast -a com.android.systemui.screenshot.ScreenshotService.ACTION_SYSTRACE.

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

Проблема решается использованием Flowable вместо Observable, поскольку Flowable поддерживает стратегию управления нагрузкой. Также применяются операторы onBackpressureBuffer, onBackpressureDrop, onBackpressureLatest и управление запросами вручную.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
🤔 В чём отличие Dalvik Virtual Machine и ART(Android Run Time)?

Dalvik Virtual Machine (DVM) и Android Runtime (ART) — это две среды выполнения для запуска Android-приложений. DVM использовалась в ранних версиях Android, в то время как ART пришла на замену DVM, начиная с Android 5.0 (Lollipop). Основное различие между ними заключается в способе выполнения кода и производительности.

🚩Основные отличия между Dalvik и ART

🟠Тип выполнения кода
Dalvik Virtual Machine (DVM): Just-In-Time (JIT) компиляция
Dalvik использует JIT-компиляцию (Just-In-Time), что означает, что код приложения компилируется в машинный код во время выполнения (runtime).
Когда приложение запускается, DVM интерпретирует байт-код (.dex-файлы), а при необходимости компилирует часть кода "на лету" для повышения производительности.
Этот подход требует дополнительных ресурсов во время работы приложения, что увеличивает задержки (лаг) при запуске и потребляет больше CPU и батареи.
ART использует AOT-компиляцию (Ahead-Of-Time), которая компилирует весь код приложения в машинный код заранее — во время установки приложения.
Это устраняет необходимость интерпретации и JIT-компиляции во время работы приложения, что снижает нагрузку на процессор и улучшает производительность.

🟠Производительность
Dalvik (DVM):
Поскольку JIT-компиляция происходит во время работы приложения, это создает дополнительную нагрузку на процессор и замедляет выполнение.
Производительность ниже из-за частой интерпретации кода.
ART:
Благодаря AOT-компиляции приложения запускаются быстрее и работают плавнее.
Потребление ресурсов (CPU, батарея) значительно ниже, поскольку интерпретация и компиляция кода уже выполнены на этапе установки.

🟠Ускорение запуска приложений
Dalvik (DVM):
Приложения запускаются медленнее, так как DVM интерпретирует код во время каждого запуска.
ART:
Приложения запускаются быстрее, так как код уже компилирован в машинный код на этапе установки.

🟠Потребление батареи
Dalvik (DVM):
Потребляет больше батареи из-за того, что JIT-компиляция выполняется постоянно во время работы приложения.
ART:
Более энергоэффективен, так как большая часть работы выполнена заранее, и процессор не нагружается так сильно.

🟠Время установки приложения
Dalvik (DVM):
Приложения устанавливаются быстрее, так как код не компилируется заранее.
ART:
Приложения устанавливаются медленнее, так как на этапе установки выполняется AOT-компиляция.
Например, установка приложения в ART может занимать больше времени, чем в DVM, из-за компиляции кода.

🟠Память
Dalvik (DVM):
DVM использует меньше памяти на устройстве, так как код компилируется только во время работы приложения, и машинный код не сохраняется.
ART:
AOT-компиляция увеличивает размер приложения, так как компилированный машинный код сохраняется на устройстве. Это требует больше места в памяти.

🟠Отладка и инструменты
Dalvik (DVM):
Ограниченные возможности отладки, так как JIT-компиляция не предоставляет доступа к заранее оптимизированному коду.
ART:
ART позволяет разработчикам использовать более продвинутые инструменты отладки (например, профилирование исполнения) и лучше анализировать производительность приложений.

🟠Совместимость
Dalvik (DVM):
Dalvik был изначально разработан для устройств с ограниченными ресурсами (медленные процессоры, малый объем оперативной памяти).
Приложения работали в основном в условиях ограниченного оборудования.
ART:
ART ориентирован на современные устройства с мощными процессорами и большим объемом памяти.
Он лучше справляется с современными требованиями приложений.

🚩Пример различий

🟠На Dalvik (DVM):
- Установка быстрая.
- При запуске приложения DVM интерпретирует и компилирует код. Это требует времени и ресурсов.
- Приложение может работать медленно из-за интерпретации кода в реальном времени.
🟠На ART:
- Установка занимает больше времени, так как код компилируется сразу.
- Запуск приложения быстрый, потому что код уже готов к исполнению.
- Приложение работает плавно, так как отсутствует необходимость компиляции во время выполнения.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 Чем array отличается от list?

В Kotlin `array` представляет собой фиксированный набор элементов одного типа, размер которого задается при создании. `List` может быть изменяемым (MutableList) или неизменяемым, и его размер может изменяться динамически. `List` предоставляет больше функциональности для работы с коллекциями данных.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
🤔 Расскажи о контрактах equals и hashCode

Методы equals() и hashCode() используются для сравнения объектов и их корректной работы в коллекциях (Set, Map).

🚩Контракт `equals()`

Метод equals() должен:
Рефлексивность: a.equals(a)true (объект равен самому себе).
Симметричность: a.equals(b) == b.equals(a).
Транзитивность: если a == b и b == c, то a == c.
Согласованность: если a == b, то a.equals(b) всегда возвращает одно и то же, пока объект не изменится.
Сравнение с null всегда даёт false: a.equals(null) == false.
class User(val name: String, val age: Int) {
override fun equals(other: Any?): Boolean {
if (this === other) return true // Проверка на ссылочное равенство
if (other !is User) return false // Проверка типа

return name == other.name && age == other.age // Сравнение полей
}
}


val user1 = User("Alice", 25)
val user2 = User("Alice", 25)
println(user1 == user2) // true (потому что переопределён equals)


🚩Контракт `hashCode()`

Метод hashCode() должен:
Согласованность с equals(): если a == b, то a.hashCode() == b.hashCode().
Но обратное не обязательно: два разных объекта могут иметь одинаковый hashCode().
Хеш-код не должен меняться, если объект не изменился.
class User(val name: String, val age: Int) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is User) return false
return name == other.name && age == other.age
}

override fun hashCode(): Int {
return name.hashCode() * 31 + age // 31 - стандартный коэффициент
}
}


val userSet = HashSet<User>()
userSet.add(User("Alice", 25))
println(userSet.contains(User("Alice", 25))) // true


🚩Автоматическая генерация в Kotlin

Чтобы не писать equals() и hashCode() вручную, можно использовать data class:
data class User(val name: String, val age: Int)


data class автоматически создаёт equals(), hashCode(), а также copy() и toString().
val user1 = User("Alice", 25)
val user2 = User("Alice", 25)
println(user1 == user2) // true (equals)
println(user1.hashCode() == user2.hashCode()) // true


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

Dagger — это статически проверяемый фреймворк для внедрения зависимостей. Он генерирует код на этапе компиляции, обеспечивая высокую производительность и удобное масштабирование.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1💊1
🤔 Какие стратегии бранчинга знаешь, расскажи про их плюсы и минусы?

Бранчинг (ветвление) — это способ управления кодом в Git, когда разработчики работают в отдельных ветках (branches).
Основные стратегии бранчинга
Git Flow
GitHub Flow
GitLab Flow
Trunk-Based Development

🚩Git Flow – классическая модель с `develop` и `release`

Основные ветки:
main (стабильная версия, релизы).
develop (основная ветка разработки).
Временные ветки:
feature/* (новые фичи, мерджатся в develop).
release/* (готовится релиз, тестирование, фикс багов).
hotfix/* (критические фиксы в main).
Схема Git Flow:
main ──── hotfix ─▶️ merge ────▶️ main

├── develop ─▶️ release ─▶️ merge ─▶️ main
│ │
├── feature/1
├── feature/2


🚩GitHub Flow – упрощённый процесс для CI/CD

Только две основные ветки:
main (всегда стабильная версия).
Фичи разрабатываются в feature/* и сразу мерджатся в main.
Деплой возможен сразу после мерджа в main.
Схема GitHub Flow
main ────▶️ feature/1 ─▶️ merge ─▶️ main ─▶️ deploy
└── feature/2 ─▶️ merge ─▶️ main ─▶️ deploy


🚩GitLab Flow – баланс между Git Flow и GitHub Flow

main – стабильная ветка (готовая к продакшену).
develop (опционально) – если нужно тестирование перед main.
feature/* – для разработки новых фич.
production, staging – если нужно разделение сред.
hotfix/* – фиксы продакшена.
main ────▶️ production

├── staging ───▶️ merge ─▶️ main

├── feature/1 ─▶️ merge ─▶️ staging
├── feature/2 ─▶️ merge ─▶️ staging


🚩Trunk-Based Development – одна ветка (`main`)

Разработчики работают прямо в main, без feature/* веток.
- Коммиты в main маленькие и частые.
- Используются Feature Flags (фичи включаются/выключаются динамически).
Схема Trunk-Based
main ────▶️ commit ─▶️ commit ─▶️ commit ─▶️ deploy


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2💊1
🤔 Какие есть аналоги библиотеки Hilt?

Основные альтернативы — Dagger (ручная конфигурация), Koin (написан на Kotlin, декларативный), Kodein (устаревающий), Service Locator. Выбор зависит от предпочтений и архитектуры проекта.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1💊1
🤔 Расскажи про ключевое слово Object в Kotlin?

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

🟠Объявление объекта-одиночки (Singleton)
Kotlin предоставляет встроенную поддержку для создания singleton-объектов. Это объект, который имеет единственный экземпляр в приложении.
object Database {
val name = "MainDatabase"
fun connect() {
println("Подключение к базе данных $name")
}
}

fun main() {
Database.connect() // Подключение к базе данных MainDatabase
}


🟠Анонимные объекты
Ключевое слово object может использоваться для создания анонимных объектов (объектов без имени). Это полезно, если нужно создать временный объект или реализовать интерфейс/абстрактный класс.
fun main() {
val listener = object : ClickListener {
override fun onClick() {
println("Кнопка нажата")
}
}
listener.onClick()
}

interface ClickListener {
fun onClick()
}


🟠Компаньон-объекты (Companion Object)
Ключевое слово object можно использовать внутри класса для объявления компаньон-объекта. Это позволяет создавать статические методы и переменные в классе.
class User(val name: String) {
companion object {
fun createGuest() = User("Guest")
}
}

fun main() {
val guest = User.createGuest()
println(guest.name) // Guest
}


🟠Объект-выражение
Ключевое слово object может использоваться для объявления объектов в коде прямо "на месте".
val myObject = object {
val x = 10
fun printX() {
println(x)
}
}

fun main() {
myObject.printX() // 10
}


🚩Почему `object` так полезен?

🟠Лаконичность
Вместо написания множества шаблонного кода для Singleton, анонимных объектов или статических методов, вы получаете готовую реализацию из коробки.

🟠Потокобезопасность
В случае object, компилятор Kotlin автоматически гарантирует, что объект создаётся в потокобезопасном режиме.

🟠Гибкость
object можно использовать практически везде: глобально, локально, внутри классов и функций.

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

Гонки происходят, когда два потока одновременно обращаются к общим данным без синхронизации. Решения:
- synchronized,
- ReentrantLock,
- Atomic-типы,
- volatile — только если нужна гарантия видимости, но не атомарности.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 Расскажи про коллекцию Map

Map – это коллекция пар ключ-значение. Каждый ключ уникален, а значения могут повторяться. В Kotlin Map не наследуется от Collection, но является частью стандартных коллекций.

🟠Виды `Map` в Kotlin
В Kotlin есть два основных типа Map:
Map (неизменяемая) – нельзя добавлять/удалять элементы после создания.
MutableMap (изменяемая) – можно добавлять, удалять и изменять элементы.

Создаётся с помощью mapOf()
val users = mapOf(1 to "Alice", 2 to "Bob", 3 to "Charlie")
println(users[1]) // Выведет: Alice


Создаётся с помощью mutableMapOf()
val users = mutableMapOf(1 to "Alice", 2 to "Bob")
users[3] = "Charlie" // Добавляем элемент
users[1] = "Alex" // Изменяем значение по ключу
users.remove(2) // Удаляем элемент
println(users) // {1=Alex, 3=Charlie}


🟠Основные операции с `Map`
map[key] – получить значение (или null, если ключа нет).
map.getValue(key) – получить значение (или исключение, если ключа нет).
map.getOrDefault(key, defaultValue) – вернуть значение или defaultValue, если ключа нет.
map.getOrElse(key) { default } – если ключа нет, выполнить лямбда-выражение.
val users = mapOf(1 to "Alice", 2 to "Bob")
println(users[1]) // Alice
println(users.getOrDefault(3, "Unknown")) // Unknown


🟠Проверка наличия ключей и значений
map.containsKey(key) – есть ли ключ?
map.containsValue(value) – есть ли значение?
println(users.containsKey(2))  // true
println(users.containsValue("Charlie")) // false


Перебор элементов
for ((key, value) in users) {
println("ID: $key, Name: $value")
}


Фильтрация Map
val filtered = users.filter { (key, value) -> key % 2 == 0 }
println(filtered) // {2=Bob}


🚩Особенности `Map` в Kotlin

🟠Порядок элементов
mapOf() – не гарантирует порядок. linkedMapOf() – сохраняет порядок добавления.
🟠Производительность
Обычный HashMap (mutableMapOf()) – O(1) для поиска по ключу. TreeMapO(log n), но поддерживает сортировку по ключам.

val sortedUsers = sortedMapOf(3 to "Charlie", 1 to "Alice", 2 to "Bob")
println(sortedUsers) // {1=Alice, 2=Bob, 3=Charlie}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Фреймворк Dagger

Dagger — это фреймворк для внедрения зависимостей в Java и Kotlin. Он использует аннотации для описания зависимостей и автоматического их создания. Dagger генерирует код на этапе компиляции, который управляет зависимостями и предоставляет их нуждающимся классам. Он основан на принципах инверсии управления и часто используется для масштабируемых приложений, таких как Android-приложения. В Android Dagger помогает удобно управлять зависимостями, улучшая тестируемость и читаемость кода.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 Расскажи про инициализаторы в классах в Kotlin

В Kotlin инициализаторы используются для выполнения кода при создании экземпляра класса.
Первичный (primary) конструктор
Вторичные (secondary) конструкторы
Инициализационный блок (init)

🟠Первичный конструктор
Это основной способ инициализации класса в Kotlin. Он объявляется в заголовке класса.
class User(val name: String, val age: Int)


Если нужно выполнить дополнительную логику во время создания объекта, используют блок init:
class User(val name: String, val age: Int) {
init {
println("Создан пользователь: $name, возраст: $age")
}
}


🟠Вторичные конструкторы
Они объявляются с помощью constructor и нужны, если:
Нужно несколько способов создания объекта.
Надо вызвать другой конструктор (this(...)).
class User {
var name: String
var age: Int

constructor(name: String) {
this.name = name
this.age = 18 // Значение по умолчанию
}

constructor(name: String, age: Int) {
this.name = name
this.age = age
}
}


Можно создать объект так
val user1 = User("Алекс")   // возраст будет 18  
val user2 = User("Иван", 25)


Если есть первичный конструктор, вторичный должен его вызывать через this(...)
class User(val name: String, val age: Int) {
constructor(name: String) : this(name, 18)
}


🟠`init` vs вторичный конструктор
init выполняется всегда при вызове первичного конструктора.
Вторичный конструктор создаёт альтернативный способ создания объекта.
class User(val name: String, val age: Int) {
init {
println("Создан пользователь: $name, возраст: $age")
}

constructor(name: String) : this(name, 18) {
println("Вызван вторичный конструктор")
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 В Android существуют мэпы, в которые можно положить примитивные типы?

Да, существуют специализированные реализации мэп, оптимизированные под примитивы, например:
- SparseIntArray — аналог Map<Int, Int>, но без обёртки Integer.
- SparseBooleanArray, SparseArray<T> и другие.
Они используются для экономии памяти и производительности, избегая автоупаковки (autoboxing).


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