uz
Feedback
Kotlin | Вопросы собесов

Kotlin | Вопросы собесов

Kanalga Telegram’da o‘tish

Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @sendme_ads

Ko'proq ko'rsatish
2 455
Obunachilar
Ma'lumot yo'q24 soatlar
+47 kun
+730 kun
Postlar arxiv
🤔 Расскажи подробно, что из себя представляет каждый компонент А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"))
Ставь 👍 и забирай 📚 Базу знаний

🔥 Скрытые вакансии с удаленной работой для Android разработчика, которые нигде больше не публикуются. Напрямую от компаний,
🔥 Скрытые вакансии с удаленной работой для Android разработчика, которые нигде больше не публикуются. Напрямую от компаний, с контактами рекрутеров. 🔹 Android Jobs | Вакансии 🔹 Flutter Dart Jobs | Вакансии 🔹 iOS Jobs | Вакансии 🔸 Все каналы с вакансиями

🤔 Что известно про генерации Young, Old в GC? - Young Generation: - Содержит новые объекты. - Быстрое создание и удаление. - Делится на Eden и два Survivor-пула. - GC здесь называется Minor GC и работает быстро. - Old Generation (Tenured): - Хранит объекты, пережившие несколько циклов GC. - Удаление объектов тут требует более тяжёлой и полной сборки — Major GC. Такой подход (генерационная модель) помогает оптимизировать производительность, так как большинство объектов "умирает молодыми". Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Чем отличаются data-классы и sealed-классы? data class — класс для хранения данных с автогенерацией equals(), hashCode(), copy(). sealed class — ограниченная иерархия классов, используется для when. 🚩`data class` – для хранения данных data class автоматически создаёт: equals() и hashCode() → сравнение объектов по значениям. copy() → удобное копирование с изменением параметров. toString() → красивый вывод.
data class User(val id: Int, val name: String)

fun main() {
    val user1 = User(1, "Alice")
    val user2 = user1.copy(name = "Bob") // Создаём копию с новым именем

    println(user1) // User(id=1, name=Alice)
    println(user2) // User(id=1, name=Bob)
}
🚩`sealed class` – для ограниченных иерархий классов sealed class используется, когда есть фиксированное число подклассов.
sealed class NetworkState {
    object Loading : NetworkState()
    data class Success(val data: String) : NetworkState()
    data class Error(val message: String) : NetworkState()
}

fun handleState(state: NetworkState) {
    when (state) {
        is NetworkState.Loading -> println("Загрузка...")
        is NetworkState.Success -> println("Данные: ${state.data}")
        is NetworkState.Error -> println("Ошибка: ${state.message}")
    }
}
🚩Можно ли использовать `data class` внутри `sealed class`? Да! Это лучший вариант для управления состояниями:
sealed class Result {
    object Loading : Result()
    data class Success(val data: String) : Result()
    data class Error(val message: String) : Result()
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Разница Iteration и Enumeration? - Enumeration — устаревший интерфейс, используется в старых коллекциях (Vector). - Iterator — современный подход с возможностью безопасного удаления (remove()) элементов во время итерации. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое SharedFlow и чем он отличается от StateFlow? В Kotlin Flow есть два специальных вида потоков для управления состоянием и передачей данных: StateFlow — используется для хранения и отслеживания состояния. SharedFlow — используется для многократной отправки данных нескольким подписчикам. Теперь разберёмся в деталях. 🚩Что такое SharedFlow? SharedFlow — это горячий (hot) поток, который можно использовать для передачи данных нескольким подписчикам. Он не хранит состояние и просто раздаёт значения подписчикам в реальном времени. 🚩Как работает SharedFlow? - Позволяет многим подписчикам получать одни и те же данные. - Может буферизировать значения (хранить их для новых подписчиков). - Может повторять последние значения (replay) для новых подписчиков. - Может накапливать данные и работать как очередь событий.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
    val sharedFlow = MutableSharedFlow<Int>(replay = 2) // Будет повторять последние 2 значения для новых подписчиков

    launch {
        for (i in 1..5) {
            sharedFlow.emit(i)
            delay(100)
        }
    }

    launch {
        delay(150) // Подписываемся чуть позже
        sharedFlow.collect { println("Первый подписчик получил: $it") }
    }

    launch {
        delay(300) // Подписываемся ещё позже
        sharedFlow.collect { println("Второй подписчик получил: $it") }
    }
}
🚩Что такое StateFlow? StateFlow — это поток, который всегда хранит одно последнее значениЕ. Он идеально подходит для представления состояния (например, UI-состояния в MVVM). - Всегда содержит одно актуальное значение. - Если новое значение не отличается от текущего, оно не отправляется подписчикам. - Новый подписчик сразу получает текущее значение. - Можно думать о StateFlow как о LiveData, но для корутин.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
    val stateFlow = MutableStateFlow(0) // Начальное состояние

    launch {
        delay(200) // Подписываемся позже
        stateFlow.collect { println("Подписчик получил: $it") }
    }

    delay(100)
    stateFlow.value = 1 // Меняем состояние
    stateFlow.value = 2 // Меняем состояние
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое утечки памяти? Утечки памяти возникают, когда объекты в памяти больше не используются, но продолжают удерживаться из-за активных ссылок, которые на них ссылаются. 1. В языках с автоматическим управлением памятью, таких как Java или Python, утечки обычно вызваны циклическими ссылками или неправильным использованием коллекций. 2. В языках со статическим управлением памятью, таких как C++, утечки происходят из-за отсутствия освобождения памяти после выделения (например, забыли вызвать delete после new). 3. Основная проблема утечек — рост потребления памяти, что может привести к замедлению программы или её краху. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Как запустить асинхронные операции в чистом Android? В Android существует несколько способов запуска асинхронных операций. Наиболее распространённые из них включают использование AsyncTask (хотя он уже устарел), HandlerThread, AsyncTaskLoader, ExecutorService и современные подходы с использованием Kotlin Coroutines и библиотеки WorkManager. 🟠AsyncTask (устаревший) AsyncTask был одним из первых инструментов для выполнения асинхронных задач, однако его использование сейчас не рекомендуется из-за проблем с управлением жизненным циклом и утечками памяти.
private class MyAsyncTask extends AsyncTask<Void, Void, String> {
    @Override
    protected String doInBackground(Void... voids) {
        // Выполнение длительной операции
        return "Result";
    }

    @Override
    protected void onPostExecute(String result) {
        // Обновление UI после завершения операции
    }
}

// Запуск
new MyAsyncTask().execute();
🟠HandlerThread HandlerThread — это удобный способ создания фонового потока с циклом обработки сообщений.
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());

handler.post(new Runnable() {
    @Override
    public void run() {
        // Выполнение длительной операции
    }
});
🟠ExecutorService ExecutorService из стандартной библиотеки Java предоставляет более гибкий способ управления потоками.
ExecutorService executor = Executors.newSingleThreadExecutor();

executor.submit(new Runnable() {
    @Override
    public void run() {
        // Выполнение длительной операции
    }
});
🟠Kotlin Coroutines Корутины в Kotlin — это современный и мощный инструмент для асинхронного программирования. Они упрощают работу с асинхронными задачами и обеспечивают безопасность работы с UI.
import kotlinx.coroutines.*

fun performAsyncTask() {
    GlobalScope.launch(Dispatchers.IO) {
        // Выполнение длительной операции
        val result = longRunningTask()

        withContext(Dispatchers.Main) {
            // Обновление UI после завершения операции
        }
    }
}

suspend fun longRunningTask(): String {
    delay(1000) // Симуляция длительной операции
    return "Result"
}
🟠WorkManager WorkManager — это библиотека для выполнения фоновых задач, которая обеспечивает выполнение задач даже после закрытия приложения или перезагрузки устройства.
public class MyWorker extends Worker {
    public MyWorker(@NonNull Context context, @NonNull WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        // Выполнение длительной операции
        return Result.success();
    }
}

// Запуск Worker
WorkManager workManager = WorkManager.getInstance(context);
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(MyWorker.class).build();
workManager.enqueue(request);
🟠RxJava RxJava — это библиотека для реактивного программирования, которая также может быть использована для выполнения асинхронных задач.
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;

Observable.fromCallable(() -> {
    // Выполнение длительной операции
    return "Result";
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
    // Обновление UI после завершения операции
});
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что известно про аннотации Dagger Provide и Binds? - @Provide: - Используется, когда ты сам создаёшь объект вручную. - Возвращает конкретную реализацию зависимости. - Гибко и подходит для конструкций с логикой. - @Binds: - Используется, если реализация уже доступна через конструктор. - Просто указывает, какой интерфейс соответствует какому классу. - Требует абстрактной функции и не допускает тела метода. Обычно @Provide применяют при сложной логике создания, а @Binds — при простом сопоставлении интерфейса и реализации. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Как собираем код? Сборка Android-приложения проходит несколько этапов: Компиляция (.kt/.java → .class → .dex) Объединение ресурсов (XML, PNG → R.java) Сборка APK/AAB Подписывание и оптимизация Установка и запуск на устройстве 🚩Компиляция кода (`.kt/.java → .dex`) Компиляция Kotlin/Java в байткод JVM (.class) Kotlin-код (.kt) → Java-байткод (.class) Java-код (.java) → .class - Используются компиляторы: - kotlinc (Kotlin Compiler) - javac (Java Compiler)
// Kotlin-код (MainActivity.kt)
fun main() {
    println("Привет, Android!")
}
kotlinc MainActivity.kt -d MainActivity.class
Преобразование .class в `.dex* Android не использует байткод JVM, а преобразует .class в Dalvik Executable (.dex).
d8 MainActivity.class --output classes.dex
🚩Компиляция ресурсов (`XML, PNG → R.java → .dex`) Android Gradle Plugin (AGP) обрабатывает ресурсы - res/layout/*.xml → UI файлы - res/drawable/*.png → Иконки - AndroidManifest.xml → Метаинформация
public final class R {
    public static final class layout {
        public static final int activity_main = 0x7f0a0000;
    }
}
🚩Сборка APK/AAB APK (старый формат) и AAB (новый формат Google Play) classes.dex + res/ + AndroidManifest.xml объединяются Проходит обфускация (ProGuard / R8) APK/AAB упаковывается в ZIP-архив
zipalign -v 4 app.apk signed_app.apk
🚩Подписывание и оптимизация APK/AAB должен быть подписан перед установкой
apksigner sign --ks my-release-key.jks --out signed_app.apk app-release.apk
Установка и запуск
adb install signed_app.apk
adb shell am start -n com.example.app/.MainActivity
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое Extensions? Термин "Extensions" (расширения) используется для обозначения функциональности, которая позволяет добавлять новые возможности к существующим классам без изменения их исходного кода. Этот концепт особенно популярен к примеру в Swift и Kotlin, где расширения используются для улучшения читаемости кода, упрощения его структуры и добавления удобных методов для работы с уже существующими типами данных. 🚩Расширения в Kotlin Расширения позволяют добавить новую функциональность к классам, даже если исходный код этих классов недоступен для изменений (например, классы из стандартной библиотеки или сторонних библиотек). Это делается путём объявления функций или свойств, которые могут быть вызваны на экземплярах этих классов, как если бы они были частью оригинальных классов.
// Расширение класса String для проверки, пуста ли строка или состоит из пробелов
fun String.isNullOrBlank(): Boolean {
    return this == null || this.trim().isEmpty()
}

// Использование расширения
val myString = "  "
println(myString.isNullOrBlank()) // Выведет: true
🚩Расширения в Swift Использует очень похожий подход, позволяя добавлять новые методы и вычисляемые свойства к существующим типам. Расширения могут даже добавлять новые протоколы к типам, что делает их чрезвычайно мощным инструментом в разработке под iOS и macOS.
// Расширение стандартного типа String для добавления метода инвертирования строки
extension String {
    func reversedString() -> String {
        return String(self.reversed())
    }
}

let myString = "Hello"
print(myString.reversedString()) // Выведет: "olleH"
🚩Плюсы ➕Улучшение читаемости и организации кода Расширения позволяют держать методы, связанные с определёнными типами данных, ближе к использованию этих типов. ➕Избегание наследования Расширения предоставляют альтернативный способ добавления функциональности к классам без использования наследования, что помогает избежать избыточной иерархии и увеличения сложности системы. ➕Реиспользование кода Методы, добавленные через расширения, могут быть легко переиспользованы в различных частях приложения. Ставь 👍 и забирай 📚 Базу знаний

🤔 Что нужно сделать в 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
#### Пример простого макета:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Привет, мир!"
        android:textSize="24sp"
        android:padding="16dp"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Нажми меня"/>
</LinearLayout>
🟠Подключение макета к активности Макет нужно связать с логикой приложения в Java или Kotlin. Это делается с помощью метода setContentView() в Activity.
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Указываем, какой XML-файл использовать для интерфейса
        setContentView(R.layout.activity_main)

        // Найдём элементы интерфейса и добавим логику
        val textView = findViewById<TextView>(R.id.textView)
        val button = findViewById<Button>(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. Убедитесь, что устройство подключено или выбран эмулятор. После запуска вы увидите созданный интерфейс. Ставь 👍 и забирай 📚 Базу знаний

🤔 Как бы передавал фотографию в редактор? Передача фото в редактор зависит от типа редактора: 1. Внешний редактор (например, Google Photos, Snapseed). 2. Встроенный редактор внутри приложения. 🚩Передача фото во внешний редактор (Intent) Если редактор — другое приложение, используем Intent.ACTION_EDIT. Как передать фото в редактор?
fun openPhotoEditor(context: Context, uri: Uri) {
    val intent = Intent(Intent.ACTION_EDIT).apply {
        setDataAndType(uri, "image/*")
        addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // Разрешение на чтение
    }
    context.startActivity(Intent.createChooser(intent, "Выберите редактор"))
}
🚩Передача в `Activity` своего приложения (FileProvider) Если редактор — внутри приложения, можно передавать фото через Intent с Uri. Отправка фото в редактор
fun openEditor(context: Context, photoFile: File) {
    val uri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", photoFile)
    
    val intent = Intent(context, PhotoEditorActivity::class.java).apply {
        putExtra("PHOTO_URI", uri.toString())
    }
    
    context.startActivity(intent)
}
Получение фото в редакторе (PhotoEditorActivity)
class PhotoEditorActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val uriString = intent.getStringExtra("PHOTO_URI")
        val uri = uriString?.let { Uri.parse(it) }

        uri?.let {
            imageView.setImageURI(it) // Показываем фото
        }
    }
}
🚩Если фото приходит в `byte[]` (с сервера) Если фото уже в памяти (byte[]), можно передать его как Parcelable. Отправка
val bitmap = ... // Получили Bitmap
val byteArray = ByteArrayOutputStream().apply {
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, this)
}.toByteArray()

val intent = Intent(context, PhotoEditorActivity::class.java).apply {
    putExtra("PHOTO_BYTES", byteArray)
}

context.startActivity(intent)
Получение
val byteArray = intent.getByteArrayExtra("PHOTO_BYTES")
byteArray?.let {
    val bitmap = BitmapFactory.decodeByteArray(it, 0, it.size)
    imageView.setImageBitmap(bitmap)
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Какие есть особенности использования Nothing в дженериках Nothing в Kotlin используется как нижняя граница для дженериков, что означает, что он совместим с любым типом, но не может иметь значений. Это позволяет указывать, что функция или выражение не возвращают никакого значения, например, в случае исключений или бесконечного цикла. Nothing удобно использовать в дженериках для создания функций, которые гарантированно завершат выполнение программы или выбросят исключение. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Как LeakCanary находит ссылку на уничтоженную Activity? Использует комбинацию слабых ссылок (WeakReference), анализ кучи и цепочек удержания, чтобы найти ссылки на уничтоженные Activity или другие объекты, которые должны были быть освобождены сборщиком мусора. Вот более подробное объяснение того, как это работает: 🚩Шаги 1⃣Создание слабой ссылки (WeakReference) Когда Activity (или другой компонент) уничтожается, LeakCanary создает слабую ссылку на этот объект.
val weakReference = WeakReference(activity)
2⃣Ожидание сборки мусора (Garbage Collection) LeakCanary инициирует сборку мусора, чтобы попытаться освободить уничтоженный объект.
System.gc()
System.runFinalization()
3⃣Проверка слабой ссылки LeakCanary проверяет, освобождена ли слабая ссылка. Если объект не был освобожден, это указывает на возможную утечку памяти.
if (weakReference.get() != null) {
    // Объект все еще удерживается в памяти, вероятна утечка
}
4⃣Снимок кучи (Heap Dump) Если слабая ссылка не была освобождена, LeakCanary создает снимок кучи (heap dump) для дальнейшего анализа.
val heapDumpFile = createHeapDump()
5⃣Анализ кучи с помощью Shark LeakCanary использует библиотеку Shark для анализа снимка кучи. Shark проверяет все объекты в куче и их удерживающие ссылки.
val heapAnalyzer = HeapAnalyzer()
val analysis = heapAnalyzer.analyze(heapDumpFile)
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое px, dp, sp? В Android используются разные единицы измерения для работы с экраном, чтобы адаптировать UI под разные устройства. 🚩`px` (пиксели) – физические точки экрана px (pixel) – это самая маленькая единица изображения на экране. Не зависит от плотности экрана → на разных устройствах элементы могут выглядеть слишком маленькими или большими.
<TextView
    android:layout_width="100px"
    android:layout_height="50px"/>
🚩`dp` (density-independent pixels) – независимые от плотности пиксели dp (density-independent pixel) – это абстрактная единица измерения, которая адаптируется под плотность экрана (dpi). Рекомендуется для всех размеров UI, чтобы интерфейс выглядел одинаково на разных устройствах.
<TextView
    android:layout_width="100dp"
    android:layout_height="50dp"/>
Пример в Kotlin
val sizeInPx = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP, 100f, resources.displayMetrics
)
🚩`sp` (scale-independent pixels) – масштабируемые пиксели (для текста) sp (scale-independent pixel) – как dp, но ещё учитывает настройки шрифта пользователя. Используется только для размеров шрифтов.
<TextView
    android:text="Привет, мир!"
    android:textSize="16sp"/>
Пример в Kotlin
val textSizeInPx = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_SP, 16f, resources.displayMetrics
)
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое утечки памяти? Это ситуация, когда приложение выделяет память для каких-либо объектов, но затем не освобождает её, даже когда эти объекты больше не нужны. Это приводит к тому, что используемая память накапливается, что может со временем замедлить работу приложения и привести к его аварийному завершению (крашу) из-за нехватки доступной памяти. 🚩Почему происходят утечки памяти в Android? В Android утечки памяти могут возникнуть из-за особенностей работы виртуальной машины (ART или Dalvik), а также из-за того, что сборщик мусора (Garbage Collector, GC) не может освободить память для объектов, на которые по-прежнему существуют ссылки. Это происходит в следующих случаях: 🟠Долгоживущие ссылки Если объект ссылается на другой объект, который больше не нужен, последний не может быть освобождён GC. Например: Статические ссылки, которые продолжают "удерживать" объект. Замыкания (closures), которые хранят ссылки на контекст активности. 🟠Неявные ссылки Некоторые объекты системы Android, такие как Context, View, Handler, хранят ссылки на компоненты приложения (например, Activity), из-за чего их нельзя освободить. 🟠Неправильное использование API Ошибки, такие как регистрация слушателей (listeners) без последующей отписки, использование таймеров, которые продолжают работать даже после уничтожения активности, и так далее. 🚩Пример утечки памяти
public class MyActivity extends AppCompatActivity {
    private static TextView myTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myTextView = findViewById(R.id.my_text_view);
        myTextView.setText("Hello, Memory Leak!");
    }
}
Исправленный код
public class MyActivity extends AppCompatActivity {
    private TextView myTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myTextView = findViewById(R.id.my_text_view);
        myTextView.setText("Hello, World!");
    }
}
🚩Как избежать утечек памяти? 🟠Избегайте долгоживущих ссылок на объекты активности или контекста Не используйте static для объектов, ссылающихся на Context или Activity. Используйте WeakReference, если нужно сохранить ссылку, которая не должна блокировать сборщик мусора. 🟠Отключайте слушателей и callback-методы Если вы регистрируете слушателей (например, через setOnClickListener), обязательно удаляйте их в методах жизненного цикла, например, в onDestroy(). 🟠Осторожно используйте анонимные классы и лямбда-выражения Анонимные классы (например, Runnable, Handler) могут неявно хранить ссылки на внешние классы, что может привести к утечке памяти. 🟠Используйте инструменты для выявления утечек памяти Android Profiler: встроенный инструмент Android Studio для мониторинга использования памяти. LeakCanary: библиотека, которая автоматически обнаруживает утечки памяти в вашем приложении. Ставь 👍 и забирай 📚 Базу знаний

🤔 Как лучше всего использовать модификаторы доступа в Java? - private — для инкапсуляции данных внутри класса; - protected — если нужно разрешить доступ наследникам и классам в пакете; - public — для API, доступного извне; - package-private (без модификатора) — для доступа внутри одного пакета. Лучше всего ограничивать доступ настолько, насколько это возможно. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Вставка значения быстрее в Linked list или в Array list? 🚩Вставка в `ArrayList` ArrayList реализован на основе массива. 🟠Вставка в конец Амортизированное O(1). Если массив не заполнен, элемент добавляется в конец списка. В случае, если массив заполнен, требуется выделение нового массива и копирование элементов, что занимает O(n) времени.
val arrayList = ArrayList<Int>()
arrayList.add(1) // Быстрая вставка в конец
🟠Вставка в начало или середину O(n). Необходимо сдвинуть все элементы, начиная с позиции вставки, чтобы освободить место для нового элемента. Это требует времени, пропорционального количеству элементов после позиции вставки.
arrayList.add(0, 2) // Медленная вставка в начало
arrayList.add(1, 3) // Медленная вставка в середину
🚩Вставка в LinkedList LinkedList реализован на основе узлов, где каждый узел содержит ссылку на следующий и/или предыдущий узел (в случае двусвязного списка). 🟠Вставка в начало: O(1). Для добавления элемента в начало достаточно изменить ссылки первого узла и нового узла.
val linkedList = LinkedList<Int>()
linkedList.addFirst(1) // Быстрая вставка в начало
🟠Вставка в конец O(1) (если есть ссылка на последний узел) или O(n) (если необходимо пройти весь список). Если список двусвязный и хранится ссылка на последний элемент, вставка в конец осуществляется за O(1). В противном случае, требуется пройти весь список до конца.
linkedList.addLast(2) // Быстрая вставка в конец, если есть ссылка на последний узел
🟠Вставка в середину O(n). Необходимо пройти список до нужной позиции и изменить ссылки узлов.
linkedList.add(1, 3) // Медленная вставка в середину
Ставь 👍 и забирай 📚 Базу знаний

🤔 Из каких основных элементов состоит Dagger? Dagger – это фреймворк для внедрения зависимостей (DI), который помогает управлять созданием и передачей объектов в приложении. В основе Dagger лежат граф зависимостей, который состоит из следующих ключевых элементов: 🚩`@Module` и `@Provides` – создание зависимостей @Module – это класс, который предоставляет зависимости. @Provides – аннотация, указывающая, что метод создаёт объект для графа Dagger.
@Module
class NetworkModule {

    @Provides
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
    }
}
🟠`@Inject` – внедрение зависимостей @Inject в конструкторе – позволяет Dagger автоматически создавать объект без @Module.
class ApiService @Inject constructor(private val retrofit: Retrofit) {
    fun fetchData() { /*...*/ }
}
🟠`@Component` – связывание модулей и мест внедрения @Component – это интерфейс, который соединяет модули и классы, где нужны зависимости.
@Component(modules = [NetworkModule::class])
interface AppComponent {
    fun inject(activity: MainActivity)  // Указываем, куда внедрять зависимости
}
🟠`@Singleton` – область жизни объекта Используется для создания одного экземпляра объекта на всё приложение.
@Singleton
@Component(modules = [NetworkModule::class])
interface AppComponent
🟠`@Binds` – привязка интерфейса к реализации Если у нас есть интерфейс и его реализация, лучше использовать @Binds вместо @Provides.
interface Repository {
    fun getData(): String
}

class RepositoryImpl @Inject constructor() : Repository {
    override fun getData() = "Data from repository"
}

@Module
abstract class RepositoryModule {
    @Binds
    abstract fun bindRepository(repo: RepositoryImpl): Repository
}
🟠`Subcomponent` – вложенные компоненты Если нужно создать зависимости с разными областями жизни (например, Activity, Fragment), используют @Subcomponent.
@Subcomponent
interface ActivityComponent {
    fun inject(activity: MainActivity)
}
Ставь 👍 и забирай 📚 Базу знаний