Kotlin | Вопросы собесов
2.56K subscribers
28 photos
972 links
Download Telegram
🤔 В чём отличие андроид 7 и 8?

Различия между Android 7 (Nougat) и Android 8 (Oreo) заключаются в добавленных функциях, изменениях в производительности, безопасности, работе приложений и пользовательском интерфейсе.

🚩Основные отличия Android 7 и Android 8

🟠Производительность и оптимизация
Android 7 (Nougat):
Впервые представлена технология Doze on the Go, которая снижает энергопотребление приложений, когда устройство неактивно.
Улучшена многозадачность благодаря Split-Screen Mode (режим разделения экрана).
Android 8 (Oreo):
Введена система Vitals, которая отслеживает поведение приложений и оптимизирует их производительность, снижая потребление батареи и ресурсов.
Фоновое ограничение (Background Limits): приложения, работающие в фоновом режиме, имеют жёсткие ограничения на использование ресурсов (например, CPU и батареи).

🟠Новые функции в пользовательском интерфейсе
Android 7 (Nougat):
Режим разделения экрана (Split-Screen): позволяет одновременно запускать два приложения. Быстрая смена между последними приложениями через двойное нажатие кнопки недавних задач.
Android 8 (Oreo):
Картинка в картинке (Picture-in-Picture): возможность сворачивать видео или навигационные приложения в маленькое окно, которое остается поверх других приложений.
Уведомления стали более функциональными: появились каналы уведомлений (Notification Channels), позволяющие группировать и настраивать уведомления от приложений.
Уведомления с задержкой: появилось возможность откладывать уведомления на некоторое время (Snooze).

🟠Скорость загрузки и работа приложений
Android 7 (Nougat):
Улучшения в системе ART (Android Runtime) позволили ускорить запуск приложений по сравнению с предыдущими версиями.
Android 8 (Oreo):
Добавлена функция Instant Apps: позволяет использовать приложения без их предварительной установки.
Приложения запускаются быстрее благодаря оптимизациям ART и сокращению кода, который нужно интерпретировать при старте.

🟠Безопасность
Android 7 (Nougat):
Впервые введена функция Direct Boot, позволяющая приложениям выполнять задачи (например, будильник или приём SMS) до ввода PIN-кода.
Android 8 (Oreo):
Представлен Google Play Protect — система защиты, которая сканирует приложения на наличие вредоносного кода.
Улучшена безопасность установки приложений из сторонних источников: теперь каждое приложение требует отдельного разрешения на установку.
Укрепление работы шифрования.

🟠Медиа и графика
Android 7 (Nougat): Поддержка новых API для работы с графикой, таких как Vulkan API для улучшения производительности в играх.
Android 8 (Oreo):
Новый формат LDAC для передачи высококачественного звука через Bluetooth (например, для беспроводных наушников).
Поддержка Wide Color Gamut для улучшения отображения цветов на экранах с расширенным динамическим диапазоном (HDR).

🟠Работа с уведомлениями
Android 7 (Nougat):
Уведомления стали интерактивными, добавлена возможность ответа прямо из уведомления.
Поддержка группировки уведомлений.
Android 8 (Oreo):
Каналы уведомлений: теперь можно настроить типы уведомлений, которые вы хотите получать от приложения (например, отключить уведомления о рекламных акциях, оставив только важные).
Добавлена возможность временного откладывания уведомлений (Snooze).

🟠Дополнительные улучшения
Android 7 (Nougat):
Поддержка многоязычия: возможность выбрать несколько языков одновременно.
Android 8 (Oreo):
Автоматическое заполнение форм (Autofill): помогает автоматически заполнять пароли и другую информацию в приложениях.
Обои адаптируются под светлую или тёмную тему интерфейса.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2💊1
🤔 В чём разница между action и category у Intent?

- action — описывает действие, которое должен выполнить Intent (например, VIEW, EDIT).
- category — определяет тип компонентов, которые могут обработать Intent (например, LAUNCHER, DEFAULT).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
🤔 Изменится ли объём памяти стека/кучи,если в приложении создано несколько потоков?

Да, объём стека изменится, а вот объём кучи останется неизменным (но нагрузка на неё увеличится).

🚩Что происходит со стеком при создании нового потока?

Стек (Stack) — это область памяти для локальных переменных и вызовов функций.
- У каждого потока (Thread) есть свой отдельный стек.
- Размер стека фиксирован и устанавливается при создании потока.
- Чем больше потоков, тем больше памяти выделяется под стеки.
Если размер стека 1 МБ, и мы создаём 100 потоков, то под стеки уйдёт 100 МБ памяти.

🚩Что происходит с кучей (Heap) при создании потоков?

Куча (Heap) — это область памяти для объектов.
- Куча общая для всех потоков.
- Новый поток не создаёт отдельную кучу, он использует ту же самую.
- Но больше потоков → больше создаваемых объектов → больше нагрузка на сборщик мусора (GC).
Вывод: Объём кучи не меняется автоматически, но может быстрее заполняться.

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

Основные методы:
- toString() — строковое представление объекта,
- equals(Object obj) — сравнение объектов,
- hashCode() — хэш-код,
- getClass() — класс объекта,
- clone() — клонирование,
- finalize() — вызывается перед сборкой мусора,
- wait(), notify(), notifyAll() — управление потоками.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
🤔 Расскажи про инициализаторы в классах в 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
🤔 В чём отличаются фреймворки Dagger и Koin?

- Dagger (включая Hilt):
- Компилируемый, статический DI.
- Высокая производительность.
- Требует больше шаблонного кода (аннотации, модули).
- Лучше подходит для крупных, долгоживущих проектов.
- Koin:
- Основан на DSL и рефлексии.
- Легче и быстрее в настройке.
- Менее производителен на старте.
- Отличен для MVP/прототипов и небольших проектов.


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

Модификаторы доступа (Access Modifiers) — это ключевые слова, которые определяют, кто может видеть и использовать класс, переменную или метод.
Они помогают инкапсулировать данные и защищать код от неправильного использования.

🚩Модификаторы доступа в Java

Пример Java
public class Example {
private int a = 10; // Только внутри класса
int b = 20; // Видно внутри пакета (package-private)
protected int c = 30; // Видно в пакете и наследниках
public int d = 40; // Доступно везде
}


🚩Модификаторы доступа в Kotlin

В Kotlin есть почти такие же модификаторы, но package-private заменён на internal.
Пример Kotlin
class Example {
private val a = 10 // Только в этом классе
internal val b = 20 // Видно в модуле
protected val c = 30 // Видно в наследниках
public val d = 40 // Видно везде (по умолчанию)
}


🚩Где используются модификаторы доступа?

Для полей (переменных класса)
public class User {
private String name; // Скрыто от других классов

public User(String name) {
this.name = name;
}

public String getName() { // Доступ через метод
return name;
}
}


Для методов
class Animal {
protected void makeSound() { // Доступен только в наследниках
System.out.println("Животное издаёт звук");
}
}
class Dog extends Animal {
public void bark() {
makeSound(); // Разрешено, потому что `protected`
System.out.println("Гав-гав!");
}
}


Для классов
public class Car { } //  Доступен везде
class Engine { } // Только в этом пакете


В Kotlin можно делать private class, но только внутри другого класса.
class Car {
private class Engine // Только в этом классе
}


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

В Java лямбды — это упрощённый синтаксис для анонимных классов, реализующих функциональный интерфейс. Синтаксис: (параметры) -> { тело }. В Kotlin лямбды представляют собой выражения, передаваемые как функции, с синтаксисом { параметры -> тело }. Kotlin более лаконичен, позволяя опускать параметры, если их можно вывести из контекста.

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

Да, Android Framework активно использует паттерн Factory в различных API. Один из самых известных примеров — LayoutInflater.

🚩Пример: `LayoutInflater` (Фабричный метод)

В Android для создания (инстанцирования) UI-компонентов из XML используется LayoutInflater, который реализует паттерн Factory Method. Вместо того чтобы вручную создавать объекты View, система предоставляет фабричный метод inflate(), который "производит" экземпляры View.

🚩Как работает?

В XML описан интерфейс.
LayoutInflater загружает XML и создает соответствующие объекты View.
Это абстрагирует создание UI-компонентов от разработчика.
val inflater = LayoutInflater.from(context)
val view = inflater.inflate(R.layout.custom_layout, parent, false)


🚩Другие примеры использования Factory в Android

🟠`MediaPlayer.create()`
Вместо MediaPlayer() напрямую используется MediaPlayer.create(context, R.raw.sound), который автоматически создаёт и настраивает объект.

🟠`PreferenceManager.getDefaultSharedPreferences()`
Позволяет получить SharedPreferences без необходимости вручную создавать экземпляр.

🟠`Fragment.instantiate()`
Фабричный метод для создания Fragment без явного вызова конструктора.

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

MV* паттерны — это архитектурные подходы, разделяющие логику приложения на слои:
- MVC (Model-View-Controller): Контроллер управляет моделью и обновляет представление.
- MVP (Model-View-Presenter): Презентер принимает действия от view, взаимодействует с моделью и обновляет UI.
- MVVM (Model-View-ViewModel): ViewModel содержит логику и состояние, а view автоматически подписана на изменения через биндинг.
Цель — отделить UI от логики и улучшить масштабируемость, читаемость и тестируемость.


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

ViewModel и onSaveInstanceState служат для сохранения данных при изменении конфигурации активности или фрагмента (например, при повороте экрана). Однако они решают эту задачу по-разному и имеют разные области применения.

🟠ViewModel
ViewModel используется для хранения и управления данными, связанных с UI, таким образом, чтобы они сохранялись при изменении конфигурации (например, при повороте экрана).

🚩Как это работает?

Когда система уничтожает и пересоздаёт Activity или Fragment, ViewModel остаётся в памяти до полного уничтожения владельца (например, выхода из Activity).
class MyViewModel : ViewModel() {
var counter: Int = 0 // Переменная, которая сохраняется при повороте экрана
}


Использование в Activity
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MyViewModel

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

viewModel = ViewModelProvider(this).get(MyViewModel::class.java)

// Теперь viewModel.counter сохранится при повороте экрана
}
}



🚩Плюсы

Хранит данные в памяти
до полного уничтожения Activity или Fragment.
Удобно для хранения сложных объектов
списки, модели, API-данные
Позволяет разделять логику и UI
улучшая архитектуру.

🚩Минусы

Данные исчезают при уничтожении Activity
например, при закрытии приложения
Не сохраняет данные при завершении процесса например, при нехватке памяти

🚩onSaveInstanceState()

Метод onSaveInstanceState() используется для сохранения данных в Bundle, который система автоматически передаёт при пересоздании Activity или Fragment.

🚩Как это работает?

Когда Activity уничтожается (например, при повороте экрана), система вызывает onSaveInstanceState(), в котором можно сохранить небольшие данные (строки, числа и т. д.). После пересоздания Activity эти данные можно восстановить из savedInstanceState.
class MainActivity : AppCompatActivity() {
private var counter: Int = 0 // Значение, которое мы хотим сохранить

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// Восстанавливаем данные, если они есть
counter = savedInstanceState?.getInt("counter_key") ?: 0
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("counter_key", counter) // Сохраняем значение перед уничтожением Activity
}
}


🚩Плюсы

Сохраняет данные даже при завершении процесса (например, при нехватке памяти).
Позволяет быстро восстановить состояние UI (например, текст в EditText).

🚩Минусы

Подходит только для небольших данных (числа, строки).
Не подходит для хранения сложных объектов (списки, большие модели, API-данные).
Требует кодирования и декодирования данных в Bundle

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

Производительность измеряется в миллисекундах времени отрисовки (measure, layout, draw). Также учитывается количество операций пересчёта и перекомпоновки. В Jetpack Compose оценивается количеством recomposition и snapshot изменений.


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

В Java есть 4 модификатора доступа, которые контролируют видимость полей, методов и классов:

🚩`private` – самый безопасный (использовать по умолчанию)

Поля почти всегда должны быть private, чтобы инкапсулировать данные. Методы тоже лучше делать private, если они не должны использоваться извне.
public class User {
private String name; // Доступен только внутри класса

public User(String name) {
this.name = name;
}

private void logUserAction() { // Только внутри класса
System.out.println(name + " совершил действие");
}
}


🚩`package-private` (без модификатора) – для классов внутри пакета

Используется, если класс не должен быть доступен за пределами пакета. Полезно для вспомогательных классов.
class FileHelper { //  Доступен только в этом пакете
static void readFile(String path) {
System.out.println("Читаем файл: " + path);
}
}


🚩`protected` – для наследников, но не для всех

protected лучше использовать только в abstract классах и для методов, которые должны быть переопределены. Не используй protected для полей → нарушает инкапсуляцию!
abstract class Animal {
protected void makeSound() { // Наследники могут переопределять
System.out.println("Какой-то звук");
}
}

class Dog extends Animal {
@Override
protected void makeSound() {
System.out.println("Гав-гав!");
}
}


🚩`public` – только если класс/метод нужен везде

Класс можно делать public, только если он должен быть доступен во всех пакетах. Не делай поля public → нарушает инкапсуляцию!
public class UserManager { //  Доступен везде
public void createUser() { // Можно вызывать в любом месте
System.out.println("Создание пользователя...");
}
}


🚩`final` и `static` – дополняем модификаторы

final class → класс нельзя наследовать.
final method → метод нельзя переопределить.
final field → переменная неизменяема (константа).
public final class MathUtils {
public static final double PI = 3.14159;
}


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

Когда выполнение suspend-функции приостанавливается (например, при delay или await), состояние функции сохраняется в continuation-объекте, а текущий поток освобождается.
Позже выполнение возобновляется с этого же места — как будто ничего не происходило. Это реализовано через стейт-машину и трансформацию кода компилятором Kotlin.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍1
🤔 Отличие sealed и enum классов

sealed class – это ограниченная иерархия классов, где можно создавать разные подклассы с разными свойствами.
enum class – это фиксированный набор однотипных объектов, которые не имеют разной структуры.

🚩`enum class` – для фиксированного набора значений

Когда значения не изменятся (например, дни недели, цвета, статусы).
Когда у всех значений одинаковая структура.
enum class Status {
LOADING, SUCCESS, ERROR
}


Можно добавлять свойства и методы
enum class Color(val hex: String) {
RED("#FF0000"),
GREEN("#00FF00"),
BLUE("#0000FF");

fun printHex() = println(hex)
}

fun main() {
val color = Color.RED
println(color.hex) // #FF0000
color.printHex() // #FF0000
}


🚩`sealed class` – для сложных состояний с разной структурой

Когда у состояний разные параметры и поведение.
Когда нужен when, который проверяет все возможные подклассы.
sealed class Status {
object Loading : Status()
data class Success(val data: String) : Status()
data class Error(val message: String) : Status()
}


Использование с when (без else)
fun handleStatus(status: Status) {
when (status) {
is Status.Loading -> println("Загрузка...")
is Status.Success -> println("Данные: ${status.data}")
is Status.Error -> println("Ошибка: ${status.message}")
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 В чём разница между let, run, also, apply?

- let — выполняет блок с результатом и возвращает последний оператор.
- run — используется для вычислений, возвращает результат.
- also — возвращает исходный объект и используется для побочных действий.
- apply — настраивает объект и возвращает его.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
🤔 В чём отличие АПК с подписью и без подписи?

APK (Android Package) — это архив с кодом приложения, ресурсами и манифестом.
Приложение должно быть подписано, чтобы его можно было установить на устройство.

🚩Неподписанный APK (`unsigned APK`)

- Это черновая версия APK, которая не имеет цифровой подписи.
- Такой APK можно запустить только в эмуляторе или при отладке (debug build).
- Google Play не принимает неподписанные APK.
При сборке debug-версии в Android Studio:
gradlew assembleDebug


Попытка установить неподписанный APK
adb install app-unsigned.apk


Ошибка
Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES]


🚩Подписанный APK (`signed APK`)

- Подписанный APK содержит цифровую подпись, которая гарантирует, что код не был изменён.
- Android проверяет ключ подписи перед установкой.
Google Play требует подписанный APK или AAB.
Как подписать APK вручную?
apksigner sign --ks my-release-key.jks --out app-signed.apk app-unsigned.apk


🚩Зачем нужна подпись?

Подпись APK гарантирует*
Целостность → код не был изменён после сборки.
Подлинность → приложение подписано разработчиком, а не злоумышленником.
Обновления → только приложения с тем же ключом могут обновлять старую версию.

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

Данные передаются с помощью специального контейнера Data, который прикрепляется к задаче при её создании. Внутри Worker эти данные можно получить через inputData, а также можно вернуть результат выполнения обратно, используя outputData, который затем доступен через LiveData или статус задачи.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
🤔 Что происходит с полями из супер-класса при наследовании data-класса?

При наследовании data class от какого-либо суперкласса в Kotlin, важно понимать, как работают свойства (поля) суперкласса и как они влияют на функциональность и структуру data class.

🚩Что происходит с полями суперкласса

🟠Наследование свойств
Поля (свойства), объявленные в суперклассе, автоматически становятся доступными в классе-наследнике. Вы можете использовать их в наследуемом классе как обычно. Однако свойства суперкласса не участвуют в автоматически сгенерированных функциях equals(), hashCode(), и toString() для data class.

🟠Автоматически сгенерированные функции в data-классе
У data class Kotlin генерирует функции equals(), hashCode(), toString(), copy() и другие. Эти функции работают только с параметрами, объявленными в первичном конструкторе data-класса. Поля, которые находятся в суперклассе, не участвуют в этих функциях.

🟠Почему поля суперкласса игнорируются
Это связано с тем, что контракт data class предполагает, что все его ключевые данные (data) определяются только параметрами первичного конструктора. Это позволяет гарантировать, что две одинаковые сущности будут сравниваться и обрабатываться корректно, основываясь только на данных самого data class.

// Суперкласс с полем name
open class Person(val name: String)

// Наследуемый data-класс
data class Employee(val id: Int, val position: String) : Person(name = "Default")


val employee1 = Employee(1, "Developer")
val employee2 = Employee(1, "Developer")

println(employee1 == employee2) // true, так как сравнение основано только на id и position
println(employee1.toString()) // Employee(id=1, position=Developer)


🟠Если нужно включить поля суперкласса в сравнение
Если вы хотите, чтобы поля суперкласса учитывались в логике equals() или hashCode(), вам нужно переопределить эти функции вручную.
data class Employee(val id: Int, val position: String) : Person(name = "Default") {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Employee || !super.equals(other)) return false
return id == other.id && position == other.position && name == other.name
}

override fun hashCode(): Int {
return 31 * super.hashCode() + id.hashCode() + position.hashCode()
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 На что обратить внимание при работе с фрагментами?

- Жизненный цикл — особенно при навигации и конфигурации.
- Утечки памяти через context/view.
- Передача аргументов через Bundle, а не напрямую.
- Подписка на данные — отвязка в onDestroyView.
- Навигация — через Navigation Component или FragmentManager.


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