и посмотреть медиа
Kotlin | Вопросы собесов
и посмотреть медиа
Вопросы для Kotlin-разработчиков с ответами.
Вопросы для Kotlin-разработчиков с ответами.
AI бот для озвучки текста и клонирования голоса в Telegram. Создавай аудио с помощью нейросети быстро и просто.
Вопросы на Kotlin-собеседованиях: расширения, корутины, коллекции. С примерами кода и объяснениями для Android и backend.
🤔 В андроиде существуют мэпы, в которые можно положить примитивные типы? Да! В Android есть специальные Map-коллекции, которые позволяют хранить примитивные типы (int, long, boolean и т. д.) без автоупаковки (autoboxing). 🚩Почему это важно? Обычные HashMap в Kotlin используют автоупаковку (Integer вместо int), что: Увеличивает потребление памяти (из-за объектов Integer, Long и т. д.). Замедляет работу (из-за ненужного создания объектов). Решение? Использовать специализированные мэпы из android.util! 🚩`SparseArray` (замена `HashMap`) Хранит пары Int → Any, но без автоупаковки. import android.util.SparseArray val sparseArray = SparseArray() sparseArray.put(1, "Привет") sparseArray.put(2, "Мир") println(sparseArray[1]) // Привет println(sparseArray[2]) // Мир 🚩`SparseIntArray` (замена `HashMap`) Хранит пары 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 пар. import android.util.SparseBooleanArray val sparseBooleanArray = SparseBooleanArray() sparseBooleanArray.put(1, true) sparseBooleanArray.put(2, false) println(sparseBooleanArray[1]) // true println(sparseBooleanArray[2]) // false 🚩`LongSparseArray` (замена `HashMap`) Оптимизирован для Long → Any?, аналог SparseArray, но с Long ключами. import android.util.LongSparseArray val longSparseArray = LongSparseArray() longSparseArray.put(10000000000L, "Длинный ключ") println(longSparseArray[10000000000L]) // Длинный ключ Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Если профайлер показывает, что какой-нибудь фрейм занял 120 миллисекунд, что это значит? В Android каждый UI-кадр (frame) должен отрисовываться не дольше 16.67 мс (при 60 FPS). Если профайлер показывает, что фрейм занял 120 мс, это означает: - Задержка в отрисовке — кадр "просел". - Произошёл jank — визуальный лаг, фриз или «дёргание» UI. - Система не успела отрисовать кадр вовремя, и пользователь видит паузу. Причины могут быть: тяжелая логика в onDraw, в ViewModel, плохая работа RecyclerView, тяжелые изображения и т.д. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Зачем нужны 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}") } } Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Какие виды анимаций есть? Существует несколько видов анимаций: анимации представлений (устаревшие), анимации свойств (property-based), анимации переходов (transition), а также анимации на основе физики. В современных приложениях чаще всего используют property-анимации или анимации из Compose и MotionLayout. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Что нужно сделать в Android-проекте чтобы начать рисовать UI на экране? Чтобы начать рисовать пользовательский интерфейс (UI) на экране в Android-проекте, необходимо выполнить несколько шагов, которые включают настройку проекта, создание макета и взаимодействие с основными компонентами Android. 1⃣Создание Android-проекта Первый шаг — создание Android-проекта в Android Studio. Это можно сделать, выбрав шаблон «Empty Activity», который предоставляет минимальный набор для разработки приложения. Укажите имя проекта. Выберите язык программирования (Java или Kotlin). Убедитесь, что минимальная версия SDK подходит для вашей целевой аудитории. 2⃣Настройка макета (XML-файл) Android UI в основном создаётся с использованием XML-файлов, которые определяют структуру интерфейса. По умолчанию файл макета находится в каталоге: res/layout/activity_main.xml #### Пример простого макета: • 🟠Подключение макета к активности Макет нужно связать с логикой приложения в Java или Kotlin. Это делается с помощью метода setContentView() в Activity. class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Указываем, какой XML-файл использовать для интерфейса setContentView(R.layout.activity_main) // Найдём элементы интерфейса и добавим логику val textView = findViewById(R.id.textView) val button = findViewById(R.id.button) button.setOnClickListener { textView.text = "Кнопка нажата!" } } } 🟠Добавление кастомного рисования (по необходимости) Если нужно нарисовать что-то вручную (например, графику, линии, или кастомные фигуры), можно создать свой собственный класс, унаследованный от View, и переопределить метод onDraw(). class CustomView(context: Context) : View(context) { private val paint = Paint().apply { color = Color.RED strokeWidth = 10f } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) // Рисуем линию canvas?.drawLine(100f, 100f, 400f, 400f, paint) } } Чтобы использовать этот класс, можно добавить его в макет или программно class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Устанавливаем кастомный View вместо макета setContentView(CustomView(this)) } } 🟠Запуск приложения Теперь можно запустить приложение на эмуляторе или реальном устройстве: Нажмите Run в Android Studio. Убедитесь, что устройство подключено или выбран эмулятор. После запуска вы увидите созданный интерфейс. Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Что известно про жизненный цикл Activity? Жизненный цикл включает стадии: onCreate, onStart, onResume, onPause, onStop, onDestroy, с возможным восстановлением через onRestart. Он критически важен для управления ресурсами, инициализацией данных и сохранением состояния. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Как решить проблему утечек памяти в RxJava? RxJava может вызывать утечки памяти, если подписки (Disposable) не очищаются правильно. Утечки памяти происходят, когда RxJava-события продолжают выполняться после уничтожения Activity/Fragment, удерживая ссылки на View или Context. 🚩Используем `CompositeDisposable` CompositeDisposable собирает все подписки и очищает их при onDestroy(). class MainActivity : AppCompatActivity() { private val disposables = CompositeDisposable() // Собираем подписки override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val disposable = Observable.interval(1, TimeUnit.SECONDS) .subscribe { println("Tick: $it") } disposables.add(disposable) // Добавляем подписку } override fun onDestroy() { super.onDestroy() disposables.clear() // ✅ Очищаем подписки, предотвращая утечку памяти } } 🚩Используем `autoDispose` (для Jetpack Lifecycle) Если используем Jetpack ViewModel или LifecycleOwner, можно автоматически отвязывать подписки. class MyFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { Observable.interval(1, TimeUnit.SECONDS) .autoDispose(viewLifecycleOwner) // ✅ Автоочистка при `onDestroyView()` .subscribe { println("Tick: $it") } } } 🚩Используем `Disposable.dispose()` вручную Если подписка не в CompositeDisposable, её можно очистить вручную. private var disposable: Disposable? = null fun startObserving() { disposable = Observable.interval(1, TimeUnit.SECONDS) .subscribe { println("Tick: $it") } } fun stopObserving() { disposable?.dispose() // ✅ Очищаем подписку } 🚩Используем `ViewModel` + `LiveData` вместо RxJava RxJava может удерживать Activity/Fragment, вызывая утечки памяти. Лучше использовать ViewModel + LiveData! class MyViewModel : ViewModel() { private val _timer = MutableLiveData() val timer: LiveData = _timer init { Observable.interval(1, TimeUnit.SECONDS) .subscribe { _timer.postValue(it) } } } Подписка в Activity (без утечек!) viewModel.timer.observe(this) { println("Tick: $it") } Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Разница между lateinit и by lazy {}? - lateinit используется для переменных, инициализация которых отложена, но будет произведена до использования. Только для var, не для примитивов. - by lazy {} — это инициализация при первом обращении, только для val. Безопасна для многопоточности по умолчанию. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Вставка значения быстрее в Linked list или в Array list? 🚩Вставка в `ArrayList` ArrayList реализован на основе массива. 🟠Вставка в конец Амортизированное O(1). Если массив не заполнен, элемент добавляется в конец списка. В случае, если массив заполнен, требуется выделение нового массива и копирование элементов, что занимает O(n) времени. val arrayList = ArrayList() arrayList.add(1) // Быстрая вставка в конец 🟠Вставка в начало или середину O(n). Необходимо сдвинуть все элементы, начиная с позиции вставки, чтобы освободить место для нового элемента. Это требует времени, пропорционального количеству элементов после позиции вставки. arrayList.add(0, 2) // Медленная вставка в начало arrayList.add(1, 3) // Медленная вставка в середину 🚩Вставка в LinkedList LinkedList реализован на основе узлов, где каждый узел содержит ссылку на следующий и/или предыдущий узел (в случае двусвязного списка). 🟠Вставка в начало: O(1). Для добавления элемента в начало достаточно изменить ссылки первого узла и нового узла. val linkedList = LinkedList() linkedList.addFirst(1) // Быстрая вставка в начало 🟠Вставка в конец O(1) (если есть ссылка на последний узел) или O(n) (если необходимо пройти весь список). Если список двусвязный и хранится ссылка на последний элемент, вставка в конец осуществляется за O(1). В противном случае, требуется пройти весь список до конца. linkedList.addLast(2) // Быстрая вставка в конец, если есть ссылка на последний узел 🟠Вставка в середину O(n). Необходимо пройти список до нужной позиции и изменить ссылки узлов. linkedList.add(1, 3) // Медленная вставка в середину Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиаТолько зарегистрированные пользователи могут делиться своим мнением.
Станьте первым, кто поделится своим впечатлением об этом ресурсе!