Kotlin | Вопросы собесов
2.56K subscribers
30 photos
972 links
Download Telegram
🤔 В чём отличие Android 4 и 5?

Android 5 (Lollipop) по сравнению с Android 4 (KitKat):
- Появился Material Design.
- Новая ART (Android Runtime) вместо Dalvik.
- Поддержка 64-битных устройств.
- Project Volta — улучшения в энергопотреблении.
- Многопользовательская поддержка на телефонах.
- Улучшенная работа с уведомлениями.


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

В Android можно создавать интерфейс без XML с помощью Jetpack Compose или программного кода (View в Kotlin/Java).

🚩Jetpack Compose — современный декларативный подход

Jetpack Compose — это новый способ создания UI в Android без XML, основанный на Kotlin.
@Composable
fun GreetingScreen() {
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Привет, мир!", fontSize = 24.sp)
Button(onClick = { println("Кнопка нажата") }) {
Text("Нажми меня")
}
}
}

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
GreetingScreen()
}
}
}


🚩Создание UI через View в Kotlin (старый способ)

Если Jetpack Compose не подходит, можно создать интерфейс программно, без XML, используя стандартные View.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// Создаём контейнер (LinearLayout)
val layout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}

// Создаём текст
val textView = TextView(this).apply {
text = "Привет, мир!"
textSize = 24f
setTextColor(Color.BLACK)
}

// Создаём кнопку
val button = Button(this).apply {
text = "Нажми меня"
setOnClickListener {
textView.text = "Кнопка нажата!"
}
}

// Добавляем элементы в контейнер
layout.addView(textView)
layout.addView(button)

// Устанавливаем UI
setContentView(layout)
}
}


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

Класс Object (в Java) и Any (в Kotlin/Scala/Swift) включает:
- equals(Object obj)
- hashCode()
- toString()
- getClass()
- wait()
- notify()
- notifyAll()
- clone()
- finalize() (устаревший)


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊5🔥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
🤔 Какой еще есть способ борьбы с гонкой потоков, кроме volatile?

- Использование блоков synchronized,
- Мьютексы,
- java.util.concurrent (например, ConcurrentHashMap),
- Иммутабельные объекты,
- Логика через ExecutorService.


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

Сильная ссылка - это ссылка, которая напрямую указывает на объект и предотвращает его сборку сборщиком мусора.

🚩Основные подходы

🟠WeakReference
Использование слабых ссылок (WeakReference) позволяет определить, был ли объект освобожден сборщиком мусора.
🟠ObjectWatcher (в LeakCanary)
LeakCanary использует ObjectWatcher для отслеживания объектов. Если объект не освобожден, ObjectWatcher уведомляет об утечке.

import java.lang.ref.WeakReference;

public class MemoryLeakExample {

public static void main(String[] args) {
// Создание объекта
MyObject myObject = new MyObject();

// Создание слабой ссылки на объект
WeakReference<MyObject> weakRef = new WeakReference<>(myObject);

// Удаление сильной ссылки
myObject = null;

// Вызов сборщика мусора
System.gc();

// Проверка, была ли слабая ссылка освобождена
if (weakRef.get() == null) {
System.out.println("Object has been garbage collected");
} else {
System.out.println("Object is still alive");
}
}

static class MyObject {
// Некоторая логика класса
}
}


🚩Понимание, что объект не используется

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

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

- ArrayList, LinkedList,
- HashSet, TreeSet, LinkedHashSet,
- HashMap, TreeMap, LinkedHashMap,
- PriorityQueue, ArrayDeque.


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

Передача больших данных (например, изображений, видео, JSON) между Activity требует оптимального подхода, потому что:
Intent.putExtra() имеет ограничение по размеру (~1MB).
Передача Bitmap в Intent может вызвать TransactionTooLargeException.
Большие данные лучше передавать через Uri, БД или FileProvider.

Неправильный способ (НЕ ДЕЛАТЬ!) – Bitmap через Intent
val bitmap: Bitmap = getBitmap()
val intent = Intent(this, ImageActivity::class.java)
intent.putExtra("image", bitmap) // ОПАСНО! Может вызвать Exception
startActivity(intent)


🚩Лучший способ – передача через `Uri` (`FileProvider`)

Сохраняем изображение во File и получаем Uri
fun saveBitmapToFile(context: Context, bitmap: Bitmap): Uri {
val file = File(context.cacheDir, "image.png")
file.outputStream().use {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, it)
}
return FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
}


Передаём Uri через Intent
val uri = saveBitmapToFile(this, bitmap)
val intent = Intent(this, ImageActivity::class.java).apply {
putExtra("image_uri", uri.toString())
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // Даем доступ другому Activity
}
startActivity(intent)


Получаем Uri в ImageActivity и загружаем изображение
val uriString = intent.getStringExtra("image_uri")
val uri = Uri.parse(uriString)

val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(uri))
imageView.setImageBitmap(bitmap)


🚩Альтернативный способ – через Базу Данных (`Room`)

Если изображение уже хранится в базе данных (Room), передаём ID записи, а не сам файл.
val intent = Intent(this, ImageActivity::class.java)
intent.putExtra("image_id", imageId) // Передаём только ID
startActivity(intent)


🚩Альтернативный способ – через `SharedPreferences` (только путь к файлу!)
Сохраняем путь
val filePath = saveBitmapToFile(this, bitmap).toString()
getSharedPreferences("app_prefs", MODE_PRIVATE).edit()
.putString("last_image", filePath)
.apply()


Читаем путь в Activity
val filePath = getSharedPreferences("app_prefs", MODE_PRIVATE)
.getString("last_image", null)
val bitmap = BitmapFactory.decodeFile(filePath)
imageView.setImageBitmap(bitmap)


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

Использовать remember, derivedStateOf, key и мемоизацию функций. Также важно следить, чтобы State не обновлялся без необходимости, а структура UI не пересоздавалась без причины.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
🤔 Если профайлер показывает тебе что какой-нибудь фрейм занял 120 миллисекунд, что это значит?

Если профайлер показывает, что рендеринг какого-либо фрейма занял 120 миллисекунд, это означает, что этот фрейм выполнялся слишком долго, что приводит к фризам и лагам в пользовательском интерфейсе.

🚩Разбор проблемы

🟠Что значит "фрейм" в этом контексте?
В Android интерфейс обновляется 60 раз в секунду (частота 60 FPS). Это значит, что каждый кадр (фрейм) должен рендериться не дольше 16,67 мс (1000 мс / 60 FPS).

🟠Почему 120 мс — это плохо?
Если рендеринг кадра занимает 120 мс, то за это время устройство должно было бы нарисовать 7 кадров (120 / 16,67 ≈ 7). Однако оно успело обработать только один, что приводит к заметному подтормаживанию.

🟠Что может вызывать такие задержки?
Тяжёлые вычисления в основном потоке (UI Thread) – например, сложные математические операции, работа с JSON, парсинг файлов.
Долгие операции с рендерингом – сложные векторные изображения, перегруженные Canvas.draw() или анимации.
Синхронные вызовы I/O (чтение файлов, базы данных, сети) – если, например, в onDraw() идёт обращение к диску или базе данных.
Неоптимальный layout – глубокая иерархия ViewGroup, частые перерасчёты макетов (measure/layout).

🚩Как исправить?

🟠Перенести тяжёлые вычисления в фоновый поток
Coroutines, Executors, WorkManager
🟠Использовать профайлер Android Studio
для поиска "узких мест".
🟠Оптимизировать рендеринг
избегать сложных onDraw(), использовать ViewStub, RecyclerView.
🟠Пересмотреть макет
убрать ненужные ViewGroup, использовать ConstraintLayout.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Что нужно сделать в Android-проекте, чтобы начать рисовать UI на экране?

Минимальные шаги:
1. Создать Activity — она является точкой входа для UI.
2. Установить content view — это может быть XML или программно созданный View.
3. Убедиться, что в манифесте указана MainActivity как LAUNCHER.
4. При запуске устройства система вызывает onCreate(), и в этот момент UI "привязывается" к экрану.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊6🔥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
🤔 Как в runtime делать динамические экраны, которые не были предусмотрены?

– Загружать конфигурацию с сервера (JSON, XML),
– Использовать Fragment/View-фабрики,
– Генерировать UI из описания,
– Использовать Jetpack Compose или RecyclerView с различными ViewType.


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

Сборщик мусора (Garbage Collector, GC) в Android (и в JVM) использует анализ ссылок для определения, можно ли уничтожить объект.

🚩Объект считается "мёртвым", если на него нет доступных ссылок

GC работает по принципу "сборки мусора с поиском корней" (Tracing Garbage Collection).

GC ищет "корневые" объекты (Root Objects) – это объекты, к которым точно есть ссылка (например, статические переменные, локальные переменные текущего потока, объекты в стеке).
GC обходит все объекты, к которым есть ссылки (прямые или косвенные).
Если объект не связан с корневыми объектами, он считается "мусором" и удаляется.
fun main() {
var user: User? = User("Alice") // Создаём объект
user = null // Теперь на объект нет ссылок, GC его удалит
}


🚩Сборщик мусора использует "Mark & Sweep"

Метод Mark & Sweep – основной алгоритм работы GC.
Mark (Пометка) – GC помечает все достижимые объекты (к которым есть ссылки).
Sweep (Очистка) – GC удаляет непомеченные объекты (на которые нет ссылок).
Root → A → B
→ C


Недостижимые объекты (GC их удаляет)
Root → A → B (C больше недоступен)

C (GC удалит!)


🚩"Сборка поколений" (Generational GC)

Объекты делятся на молодые (Young) и старые (Old)
Young Generation – новые объекты (большинство умирает быстро).
Old Generation – "долго живущие" объекты (Activity, Singleton).

🚩Что GC НЕ удаляет? (Memory Leaks)

Утечки памяти (Memory Leaks) происходят, если на объект осталась ссылка, но он больше не нужен.
class Activity {
var button: Button? = null
}

var activity: Activity? = Activity() // Создаём объект
activity?.button = Button() // `Button` ссылается на `Activity`
activity = null // Activity нельзя удалить из-за ссылки на кнопку!


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

Android 6 (Marshmallow) привнёс:
- Runtime permissions — запрашиваются во время использования, а не при установке.
- Doze mode — экономия батареи при бездействии.
- Поддержка Fingerprint API.
- Поддержка USB Type-C.
- Новый менеджер памяти (Adoptable Storage).


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

Android-приложение состоит из четырёх основных компонентов:
Activity – UI-экран приложения.
Service – фоновая работа без UI.
BroadcastReceiver – слушает системные и пользовательские события.
ContentProvider – делится данными между приложениями.

🚩`Activity` – экран приложения (UI)

Отображает интерфейс пользователя.
Обрабатывает взаимодействие (нажатия, свайпы, ввод текста).
Управляется системой через жизненный цикл (Lifecycle).
Пример Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) // Загружаем XML-разметку
}
}


🚩`Service` – фоновая работа без UI

Выполняет длительные фоновые задачи (музыка, загрузка файлов).
Может работать даже если приложение закрыто.
НЕ имеет UI (не рисует View).
Пример Service
class MyService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Thread {
// Долгая фоновая задача
}.start()
return START_STICKY
}

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


Запуск сервиса
startService(Intent(this, MyService::class.java))


Остановка сервиса
stopService(Intent(this, MyService::class.java))


🚩`BroadcastReceiver` – обработка событий (системных и пользовательских)

- Получает события системы (BOOT_COMPLETED, BATTERY_LOW).
- Слушает события других приложений.
- Может быть динамическим (через код) или статическим (AndroidManifest.xml).
Пример BroadcastReceiver (отключение Wi-Fi)
class NetworkReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == ConnectivityManager.CONNECTIVITY_ACTION) {
println("Сеть изменилась!")
}
}
}


Регистрируем BroadcastReceiver в AndroidManifest.xml
<receiver android:name=".NetworkReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>


Можно зарегистрировать динамически в коде
val receiver = NetworkReceiver()
registerReceiver(receiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))


🚩`ContentProvider` – обмен данными между приложениями

- Дает доступ к данным *другим приложениям.
- Позволяет безопасно работать с БД (Room, SQLite).
- Используется для Contacts, MediaStore, Calendar.

Пример ContentProvider (чтение контактов)
val cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null)
cursor?.use {
while (it.moveToNext()) {
val name = it.getString(it.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
println("Контакт: $name")
}
}


Запрос данных через Uri
val uri = Uri.parse("content://com.example.provider/table")
contentResolver.query(uri, null, null, null, null)


🚩Как компоненты взаимодействуют между собой?

Пример: Activity запускает Service через Intent
startService(Intent(this, MyService::class.java))

Пример: Service отправляет Broadcast, а Receiver его ловит
sendBroadcast(Intent("com.example.CUSTOM_EVENT"))


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

- Throwable — базовый.
- Error — критические ошибки JVM (не обрабатываются).
- Exception — обрабатываемые ошибки.
- RuntimeException — unchecked (например, NullPointerException).
- Остальные — checked (например, IOException, SQLException).


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

Софткод (Softcode, Soft Coding) — это подход к программированию, при котором логика программы хранится в конфигурационных файлах, базе данных или других внешних источниках, а не жёстко (hardcoded) прописана в коде.

🚩Разница между Hardcode и Softcode

Пример Hardcode (жёстко зашито в коде)
val apiUrl = "https://api.example.com" //  Если URL изменится, надо менять код


Пример Softcode (гибко через конфигурацию)
val apiUrl = Config.get("api_url") //  Загружается из настроек


🚩Где используется софткод?

Конфигурационные файлы (config.json, .properties, .xml).
База данных (логика, настройки, права пользователей).
API и сервер (получение UI-элементов, бизнес-логики с сервера).
Скриптовые языки (скрипты загружаются динамически).

🚩Примеры использования Softcode в Android

Softcode через SharedPreferences (конфигурация в памяти)
val sharedPrefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val theme = sharedPrefs.getString("app_theme", "light") // Загружаем тему из настроек


Softcode через remoteConfig (Firebase Remote Config)
val minVersion = Firebase.remoteConfig.getInt("min_supported_version")


Softcode через JSON-файл (читаем конфиг из assets)
fun getConfigValue(context: Context, key: String): String {
val json = context.assets.open("config.json").bufferedReader().use { it.readText() }
val jsonObject = JSONObject(json)
return jsonObject.getString(key) // Получаем значение из JSON
}


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

Итератор — это объект, позволяющий поэлементно перебирать коллекцию (список, массив и т.п.).
Он обычно предоставляет методы hasNext() и next() и позволяет абстрагироваться от конкретной структуры.


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

Являются двумя различными типами коллекций, которые используются для хранения наборов данных. Основные различия между этими двумя структурами данных касаются их внутренней реализации, что влияет на производительность операций добавления, удаления и доступа к элементам.

🚩Внутренняя реализация

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

🟠LinkedList
основан на двусвязном списке элементов, где каждый элемент (узел) содержит данные и ссылки на предыдущий и следующий элементы в списке. Это обеспечивает высокую производительность операций вставки и удаления, поскольку требуется лишь изменить ссылки у соседних элементов, но доступ к элементам по индексу занимает больше времени, так как для этого нужно последовательно пройти от начала или конца списка до нужного элемента.

🚩Производительность:

🟠ArrayList
Быстрый доступ к элементам по индексу. Медленные операции добавления и удаления элементов (особенно в начале и середине списка), так как может потребоваться сдвиг оставшейся части массива.

🟠LinkedList
Быстрые операции вставки и удаления элементов, поскольку они требуют только изменения ссылок. Медленный доступ к элементам по индексу, так как для доступа к элементу необходимо пройти по списку.

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

– Через Navigation Component,
– через интенты и аргументы,
– с помощью Router или Navigator при использовании архитектур (MVP, MVI),
– в многомодульности — через интерфейсы и зависимости через DI.


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