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

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

Open in Telegram

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

Show more
2 445
Subscribers
-524 hours
-157 days
-2230 days
Posts Archive
🤔 Какие есть реализации коллекций? - ArrayList, LinkedList, - HashSet, TreeSet, LinkedHashSet, - HashMap, TreeMap, LinkedHashMap, - PriorityQueue, ArrayDeque. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Зачем нужен DiffUtil? DiffUtil — это утилита для быстрого обновления списков в RecyclerView. Она сравнивает старый и новый список и находит различия, чтобы обновлять только изменённые элементы, а не весь список. 🚩Проблема без `DiffUtil` Обычное обновление списка без DiffUtil перерисовывает всё, даже если изменился один элемент.
adapter.notifyDataSetChanged() // Полностью обновляет список ❌
🟠Решение с `DiffUtil` DiffUtil находит различия между старым и новым списком и обновляет только изменённые элементы.
class MyDiffUtilCallback(
    private val oldList: List<User>,
    private val newList: List<User>
) : DiffUtil.Callback() {

    override fun getOldListSize() = oldList.size
    override fun getNewListSize() = newList.size

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition].id == newList[newItemPosition].id
    }

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition] == newList[newItemPosition] // Используем data class (авто `equals()`)
    }
}
🚩Как использовать `DiffUtil` в `RecyclerView.Adapter`? После создания DiffUtil.Callback, вызываем DiffUtil.calculateDiff() и передаём результат в adapter.
fun updateList(newList: List<User>) {
    val diffCallback = MyDiffUtilCallback(userList, newList)
    val diffResult = DiffUtil.calculateDiff(diffCallback)

    userList = newList // Обновляем старый список
    diffResult.dispatchUpdatesTo(this) // Обновляем только изменённые элементы
}
🟠`ListAdapter` – ещё проще! Если используем ListAdapter, DiffUtil уже встроен.
class UserAdapter : ListAdapter<User, UserViewHolder>(DIFF_CALLBACK) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_user, parent, false)
        return UserViewHolder(view)
    }

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        holder.bind(getItem(position)) // `getItem()` уже работает с `ListAdapter`
    }

    companion object {
        private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<User>() {
            override fun areItemsTheSame(oldItem: User, newItem: User): Boolean =
                oldItem.id == newItem.id

            override fun areContentsTheSame(oldItem: User, newItem: User): Boolean =
                oldItem == newItem
        }
    }
}
Обновление списка в ListAdapter
adapter.submitList(newList) // DiffUtil работает внутри 🚀
Ставь 👍 и забирай 📚 Базу знаний

Пожизненный PRO — по цене одного года. Покупаешь один раз — пользуешься всю жизнь: 👉 https://easyoffer.ru/pro 🚀 PRO-доступ закроет 99% проблем на пути к офферу: 1. 1100+ записей реальных собеседований (включая топы: Сбер, Авито, Яндекс, WB, OZON, МТС). Видите всё изнутри: как спрашивают, как отвечают сильные кандидаты и на каких ошибках проваливаются 80%. 2. База live-coding задач и вопросов с реальных собесов — с уникальной системой вероятности их встречи. Готовитесь не вслепую, а точечно по темам, которые спрашивают чаще всего. 3. Эталонные ответы от Senior-разработчиков. Никакой воды и догадок — только чёткие структурированные решения, за которые дают «зелёный свет» к офферу. 4. Полный доступ ко всем грейдам и профессиям. Junior вы или Senior, тестировщик, разработчик или проджект — вы получаете ВСЕ материалы easyoffer без ограничений. Безлимитно, Все, Навсегда. 5. База 400+ тестовых заданий. Прокачивайте навыки на реальных задачах — тех самых, что дают перед собесом. 6. Автоотклики на hh.ru — пока вы спите, резюме уходит рекрутерам автоматически. Экономия сотен часов ручного кликанья. 7. Аналитика ТОП-требований из вакансий. Парсим рынок и показываем, какие скиллы сейчас в цене. Апгрейдите резюме точечно и проходите ATS-фильтры (они отсеивают до 75% резюме ещё до рекрутера). 8. Генератор резюме и CV под каждую вакансию. Забудьте про «универсальное» резюме — нейросеть адаптирует ваш опыт под конкретную позицию за минуту и повышает шансы на приглашение в разы. 9. Тренажёры подготовки к собеседованию: «Реальное собеседование» — сценарий вопросов из настоящих интервью. «Проработка вопросов» — флеш-карточки по методике интервальных повторений (как Anki) 10. 🔥 Самое важное: все будущие фичи Вы платите один раз, а продукт растёт всю жизнь. Каждое обновление, каждый новый инструмент, каждая фича, которая появится за все годы проекта, автоматически падает вам в подписку без доплат. Вы фиксируете цену года, а получаете продукт, который через пару лет будет стоить в разы дороже ⭐️ Это уникальная акция пока сайт в режиме Beta. Успей ей воспользоватьсяЗавтра последний день. 👉 https://easyoffer.ru/pro

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

🔥 Осталось 3 дня! Пожизненный easyoffer PRO по цене одного года. Покупаешь один раз – пользуешься всю жизнь. Что входит в PRO: – Вопросы и задачи с реальных собеседований в конкретных компаниях – Лучшие ответы и видео-примеры от middle/senior специалистов – Записи реальных собеседований – Обход фильтров ATS с топ-30 ключевых слов в резюме – Автоотклики на hh – Тренажёры и симуляторы для идеальной подготовки к интервью ⏳ Акция действует только до 2 сентября 23:59 по МСК 👉 Забрать PRO со скидкой 70%: https://easyoffer.ru/pro

🤔 Какие знаешь особенности системы типов в Kotlin ? 🟠Null Safety (Безопасность null) Переменные по умолчанию не могут быть null, что предотвращает NullPointerException.
var a: String = "abc"
var b: String? = "abc"
b = null  // Допустимо   
🟠Коллекции (Collections) Разделение на изменяемые и неизменяемые коллекции.
val list: List<String> = listOf("a", "b", "c")  // Неизменяемый список
val mutableList: MutableList<String> = mutableListOf("a", "b", "c")  // Изменяемый список   
🟠Data Classes (Классы данных) Автоматическое создание методов equals(), hashCode(), и toString().
data class User(val name: String, val age: Int)   
🟠Smart Casts (Умные приведения типов) Автоматическое приведение типа после проверки с помощью is.
fun demo(x: Any) {
    if (x is String) {
        println(x.length)
    }
}   
🟠Sealed Classes (Запечатанные классы) Упрощают обработку ограниченных иерархий классов.
sealed class Expr
data class Const(val number: Double) : Expr()   
🟠Выведение типов (Type Inference) Kotlin автоматически определяет тип переменной.
val x = 10  // Int
Ставь 👍 и забирай 📚 Базу знаний

Ты ищешь только по верхушке айсберга 🧊 Вбиваешь «Android разработчик» и думаешь, что видел всё. А под водой скрывается ещё 8
Ты ищешь только по верхушке айсберга 🧊 Вбиваешь «Android разработчик» и думаешь, что видел всё. А под водой скрывается ещё 80% вакансий, которые называются иначе: «мобильный разработчик», «Kotlin engineer», «SDK developer» и так далее. Рекрутеры не договариваются между собой о названиях. Поэтому те, кто ищут по одному запросу, просто сливают лучшие предложения. В свежем посте на канале я собрал полный список из 15 рабочих запросов для разных площадок + список самих площадок, где эти вакансии реально публикуют. Забирай список и перестань терять вакансии 👇 Android Оффер

🤔 Какая особенность у Data Class относительно других Kotlin Classes? Data Class автоматически генерирует equals, hashCode, toString, copy, и componentN функции. Они удобны для хранения данных и значительно упрощают работу с неизменяемыми структурами. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Расскажи о контрактах 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
Ставь 👍 и забирай 📚 Базу знаний

🤔 Как работает async/await? async запускает асинхронную корутину, возвращающую Deferred, аналог Future. await приостанавливает выполнение до получения результата. Это позволяет параллельно выполнять задачи и синхронно работать с результатом. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 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 Ставь 👍 и забирай 📚 Базу знаний

🤔 Из каких более важных компонентов состоит Compose? Compose состоит из компонентов: - Composable функции: описывают UI. - State: управляет состоянием компонентов. - Modifiers: применяются для настройки внешнего вида и поведения. - Layouts: определяют структуру расположения элементов на экране. - Recomposition: механизм обновления интерфейса при изменении состояния. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Какой класс можно использовать что бы ловить разные жесты? Чтобы обрабатывать жесты в Android, используйте класс GestureDetector. Он помогает отслеживать стандартные жесты: одиночные нажатия, свайпы, долгие нажатия, двойные касания и т.д. 🚩Как использовать GestureDetector? Создайте экземпляр GestureDetector, передав Context и слушателя (GestureDetector.OnGestureListener). Передавайте события касания в gestureDetector.onTouchEvent(event) из метода onTouchEvent().
class GestureActivity : AppCompatActivity(), GestureDetector.OnGestureListener {
    private lateinit var gestureDetector: GestureDetector

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        gestureDetector = GestureDetector(this, this)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event)
    }

    override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
        val deltaX = e2!!.x - e1!!.x
        if (deltaX > 0) Log.d("Gesture", "Swipe Right") else Log.d("Gesture", "Swipe Left")
        return true
    }

    override fun onDown(e: MotionEvent?) = true
    override fun onShowPress(e: MotionEvent?) {}
    override fun onSingleTapUp(e: MotionEvent?) = false
    override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float) = false
    override fun onLongPress(e: MotionEvent?) {}
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Какие преимущества Android перед другими ОС? Android предлагает открытую экосистему, гибкость в разработке, большое количество поддерживаемых устройств и мощный инструментарий. Также Android предоставляет свободу кастомизации UI и взаимодействие с низкоуровневыми возможностями системы. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что делает библиотека LifeCycle ? Библиотека Lifecycle в Android Jetpack помогает управлять и контролировать жизненный цикл компонентов Android, таких как Activities и Fragments. Она упрощает создание компонентов, которые осведомлены о своем жизненном цикле и могут корректно реагировать на изменения в нем. Это позволяет избегать утечек памяти и некорректной работы компонентов при изменении конфигураций или переходах между состояниями. 🚩Основные компоненты библиотеки Lifecycle 🟠LifecycleOwner Это интерфейс, который определяет класс как владеющий жизненным циклом. Activity и Fragment уже реализуют этот интерфейс.
class MyActivity : AppCompatActivity(), LifecycleOwner {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}
🟠LifecycleObserver Это интерфейс, который позволяет классу наблюдать за изменениями в жизненном цикле компонента. Методы, аннотированные @OnLifecycleEvent, будут вызываться при соответствующих событиях жизненного цикла.
class MyObserver : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStart() {
        // Код, который выполняется при старте жизненного цикла
        Log.d("MyObserver", "onStart called")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onStop() {
        // Код, который выполняется при остановке жизненного цикла
        Log.d("MyObserver", "onStop called")
    }
}
🟠Lifecycle Это класс, который содержит информацию о текущем состоянии и позволяет другим объектам наблюдать за изменениями в жизненном цикле.
class MyActivity : AppCompatActivity() {
    private lateinit var myObserver: MyObserver

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

        myObserver = MyObserver()
        lifecycle.addObserver(myObserver)
    }
}
🚩Применение библиотеки Lifecycle 1⃣ Добавьте зависимости в ваш build.gradle
dependencies {
    implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
}
2⃣Создайте класс, реализующий LifecycleObserver
class MyObserver : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun onResume() {
        Log.d("MyObserver", "Activity resumed")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun onPause() {
        Log.d("MyObserver", "Activity paused")
    }
}
3⃣Добавьте LifecycleObserver в LifecycleOwner (например, Activity)
class MyActivity : AppCompatActivity() {
    private lateinit var myObserver: MyObserver

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

        myObserver = MyObserver()
        lifecycle.addObserver(myObserver)
    }
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 После перебирания данных итератором, гарантируется ли очередность получения этих данных? Гарантируется только в том случае, если структура данных поддерживает порядок (например, List, LinkedList). Если коллекция неупорядоченная (например, HashSet, HashMap.keySet()), порядок может быть произвольным и не повторяться. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Можно ли создать анонимный класс внутри inline функции? Анонимный класс внутри inline-функции будет инстанцироваться при каждом вызове функции, что ломает цель inline — избавляться от накладных расходов на объекты. 🚩Что такое анонимный класс в Kotlin? Анонимный класс — это класс без имени, который можно создать с помощью object : Interface {}.
interface ClickListener {
    fun onClick()
}

fun main() {
    val listener = object : ClickListener {
        override fun onClick() {
            println("Кнопка нажата!")
        }
    }
    
    listener.onClick()
}
🚩Анонимный класс в `inline`-функции Если мы создадим анонимный класс внутри inline-функции, он будет создаваться каждый раз при вызове функции!
inline fun setClickListener(action: () -> Unit) {
    val listener = object : ClickListener {
        override fun onClick() {
            action()
        }
    }
    listener.onClick()
}

fun main() {
    setClickListener { println("Нажато!") }
}
Ошибка компиляции
Inline function cannot contain object expressions
🚩Как обойти ограничение? Если нужно использовать inline, можно передавать лямбду вместо анонимного класса. Рабочий вариант
inline fun setClickListener(noinline action: () -> Unit): ClickListener {
    return object : ClickListener {
        override fun onClick() {
            action()
        }
    }
}

fun main() {
    val listener = setClickListener { println("Нажато!") }
    listener.onClick()
}
Ставь 👍 и забирай 📚 Базу знаний

Пожизненный PRO доступ на easyoffer — по цене одного года! До 2 сентября вы можете купить PRO навсегда. Покупаешь один раз — пользуешься всю жизнь. – База вопросов и задач из собеседований – Примеры видео-ответов на вопросы – Записи реальных собеседований – Тренажеры "Проработка вопросов" и "Реальное собеседование" – Аналитика требований из вакансий – Автоотклики на вакансии – Агрегатор вакансий (скоро) 👉 Купить PRO со скидкой 70%: https://easyoffer.ru/pro

🤔 Расскажи про data классы и sealed классы Data-классы в Kotlin предназначены для хранения данных и автоматически создают полезные методы, такие как `equals()`, `hashCode()`, `toString()`, а также методы для копирования объектов. Они удобны для представления сущностей с полями, которые нужно сравнивать, копировать или выводить, например, записи в базе данных. Sealed-классы (запечатанные классы) ограничивают наследование, позволяя создавать иерархии с фиксированным набором подклассов, что полезно для работы с типами, набор которых известен на этапе компиляции. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Расскажи подробно, что из себя представляет каждый компонент А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"))
Ставь 👍 и забирай 📚 Базу знаний