diff --git a/section/android.md b/section/android.md
index 10606c3..381dc94 100644
--- a/section/android.md
+++ b/section/android.md
@@ -7,16 +7,16 @@
- **Утечки памяти:** Утечки памяти происходят, когда объекты не освобождаются после использования, что со временем может привести к истощению доступной памяти и замедлению приложения.
- #### Что такое `Context`? Зачем он используется?
- `Context` в Android — это интерфейс, который предоставляет доступ к глобальной информации о приложении. Он используется для получения доступа к ресурсам, файловым системам, вызова активностей и служб.
- Существует три типа контекста: `ApplicationContext`, `ActivityContext`, `BaseContext`.
- 1. `ApplicationContext` связан с жизненным циклом приложения
- 2. `ActivityContext` связан с жизненным циклом активности.
- 3. `BaseContext` в Android является базовым классом контекста (`Context`). Он используется как родительский класс для `ActivityContext` и `ApplicationContext`, предоставляя основные функции контекста, которые могут быть расширены или использованы в этих специализированных контекстах. `BaseContext` обеспечивает доступ к ресурсам и системным службам, таким как запуск активностей, взаимодействие с различными сервисами Android и управление ресурсами приложения. В контексте Android разработки, когда говорят о `BaseContext`, чаще всего имеют в виду фундаментальную функциональность контекста, на которой основаны все другие типы контекстов.
+ `Context` в Android — это абстракция, которая предоставляет доступ к ресурсам приложения, системным сервисам, файловой системе, запуску компонентов и т. п. Это не интерфейс, а абстрактный класс `android.content.Context`.
+ На практике чаще всего используют:
+ 1. **`Application`-контекст** (`applicationContext`) — живет столько же, сколько процесс приложения. Подходит для долгоживущих объектов и сервисов.
+ 2. **Контекст `Activity`** — связан с жизненным циклом конкретной Activity и нужен для операций, зависящих от UI (например, инфлейт разметки с темой Activity).
+ 3. **`ContextWrapper` / `baseContext`** — обертка над контекстом, используемая для делегирования и подмены поведения (например, в `ContextThemeWrapper`).
Context необходим для:
- 1. Доступа к базовым функциям приложения, таким как доступ к ресурсам, базам данных и настройкам.
- 2. Запуска других компонентов, таких как активности и службы.
- 3. Взаимодействия с другими приложениями.
+ 1. Доступа к ресурсам, базам данных и настройкам приложения.
+ 2. Запуска компонентов (Activity, Service, BroadcastReceiver).
+ 3. Получения системных сервисов (NotificationManager, ConnectivityManager и т. п.).
- #### Назови все основные компоненты Android приложения? (4)
Основные компоненты Android приложения включают:
@@ -29,7 +29,7 @@
`AndroidManifest.xml` — это файл в Android приложении, который содержит важную информацию о приложении для Android системы. Он объявляет конфигурацию приложения, включая его компоненты (активности, службы, получатели широковещательных сообщений, поставщики контента), требуемые разрешения, минимальный уровень API Android, используемый приложением, и другие настройки. `AndroidManifest.xml` читается системой при установке приложения, и на основе этой информации система знает, как взаимодействовать с приложением.
- #### Какой компонент необязательно указывать в манифесте?
- **Broadcast Receiver** - обычно необходимо объявлять, но существует возможность динамической регистрации (в коде, а не в манифесте) для некоторых случаев использования.
+ **BroadcastReceiver** можно регистрировать динамически (через `registerReceiver`), и тогда его не нужно объявлять в манифесте. Однако на Android 8.0+ большинство неявных broadcast-ов запрещены для регистрации в манифесте, поэтому часто используют динамическую регистрацию или `WorkManager`.
- #### Что такое Application класс?
Класс `Application` в Android представляет собой базовый класс приложения, который содержит глобальное состояние приложения. Он выполняется до того, как любой другой код приложения будет запущен, и именно здесь можно инициализировать глобальные ресурсы. Класс `Application` можно использовать для выполнения действий и настройки компонентов, которые должны быть доступны во всем приложении, например, инициализации библиотек, настройки управления сессиями или предоставления контекста для использования в других компонентах приложения.
@@ -40,11 +40,11 @@
- **ActivityManager**: ActivityManager определяет, запущен ли уже процесс для этого приложения. Если процесс не запущен, система начинает процедуру его создания.
- - **Zygote**: Android использует механизм под названием Zygote для запуска процессов приложений. Zygote — это предварительно загруженный демон системы, который содержит предзагруженную виртуальную машину Dalvik или ART (в зависимости от версии Android). Когда требуется создать новый процесс приложения, Zygote порождает новый процесс путем вызова fork(). Это позволяет быстро и эффективно запускать приложения, поскольку общий код и ресурсы Android уже загружены в память.
+ - **Zygote**: Android использует механизм под названием Zygote для запуска процессов приложений. Zygote — это предварительно загруженный процесс, который содержит предзагруженную среду выполнения ART и базовые классы. При запуске нового приложения Zygote делает `fork()`, что ускоряет старт процесса.
***Запуск в контексте приложения***:
- - **Инициализация приложения**: После создания процесса для приложения система загружает Application класс приложения (если он указан) и вызывает его метод onCreate(). Это самый первый код, который исполняется в рамках процесса приложения.
+ - **Инициализация приложения**: После создания процесса система инициализирует ContentProvider (если они есть), затем создаёт `Application` и вызывает `onCreate()`. Это один из первых этапов кода в процессе приложения.
- **Запуск Activity**: После инициализации приложения система создает экземпляр основного Activity, указанного в интенте запуска, вызывая его метод onCreate(). Здесь приложение обычно загружает свой пользовательский интерфейс и выполняет начальную настройку.
@@ -60,17 +60,16 @@
Иконка приложения добавляется на рабочий стол (launcher screen) когда в манифесте приложения активити определено с интент-фильтром **ACTION.MAIN** и категорией **LAUNCHER**. При нажатии на иконку запускается активити, указанное как точка входа приложения.
- #### Что произойдет, если установить несколько активити как лаунчеры?
- Если установить несколько активити с интент-фильтром для лаунчера, пользователю будет предложен выбор активити для запуска при нажатии на иконку приложения. Это может быть использовано для предоставления различных точек входа в приложение
+ Если несколько Activity имеют `MAIN` + `LAUNCHER`, то в лаунчере появятся несколько иконок (по одной на каждую Activity), а не диалог выбора.
- #### Если бы перед вами стояла задача залогировать самую раннюю точку старта приложения, в каком месте бы вы разместили код?
- Самая ранняя точка, где можно разместить код логирования - это метод onCreate() класса Application. Этот метод вызывается при старте приложения до любого другого компонента (Activity, Service и т.д.).
-
Но и также это может быть broadcast receiver. Broadcast Receiver регистрируется для BOOT_COMPLETED и срабатывает немедленно после его получения.
+ Самая ранняя точка в процессе приложения — инициализация **ContentProvider** (его `onCreate()` вызывается до `Application.onCreate()`), поэтому для максимально раннего логирования используют ContentProvider или Jetpack App Startup. `Application.onCreate()` — первая точка, доступная во всех приложениях, но она вызывается после `ContentProvider`. BroadcastReceiver `BOOT_COMPLETED` не является точкой старта приложения; он зависит от события перезагрузки и не гарантирует ранний запуск.
- #### Можно ли обновить view из не-UI потока и с чем связано это ограничение?
Обновлять UI-компоненты (view) напрямую из не-UI потока нельзя из-за ограничений Android на доступ к UI-элементам только из главного потока. Для обновления UI из других потоков используются механизмы синхронизации, такие как `runOnUiThread()` или **Handler**.
- #### Где находится метод main() в Android приложении?
- В Android приложениях не используется метод `main()` в традиционном смысле, как в Java-приложениях. Вместо этого, точкой входа служит компонент Activity (или другие компоненты, такие как Service, BroadcastReceiver), который запускается системой Android, когда необходимо выполнить определенное действие (например, открыть приложение). Система Android использует манифест приложения для определения компонента, который должен быть запущен.
Если объявлен **Application**, то вызывается он.
+ В обычном приложении вы не пишете `main()`. Точкой входа процесса является `ActivityThread.main()` в системном коде Android, который запускается после `fork()` Zygote. Далее система создает `Application` и нужный компонент (Activity/Service/Receiver) в зависимости от интента и манифеста.
- #### Почему в классе Application есть метод onCreate, но нет метода onDestroy?
Метод `onCreate()` в классе Application вызывается при создании процесса приложения и служит для инициализации ресурсов, необходимых на протяжении всего существования приложения. Отсутствие `onDestroy()` объясняется тем, что процесс приложения уничтожается системой без каких-либо предупреждений, когда системе необходимо освободить ресурсы. Поэтому логика, требующая гарантированного выполнения перед завершением работы приложения, должна располагаться в других компонентах (например, в Activity или Service).
@@ -95,7 +94,7 @@
- #### В чем разница между `onCreate()` и `onStart()`?
Основное различие между onCreate() и onStart() заключается в их роли в жизненном цикле Activity: onCreate() служит для инициализации Activity и вызывается один раз, когда Activity создается, в то время как onStart() делает Activity видимым для пользователя и может вызываться многократно каждый раз, когда Activity переходит в видимое состояние.
- #### Когда вызывается только `onDestroy` для `Activity` без `onPause()` и `onStop()`?
- Это может произойти в крайне редких случаях, например, если система уничтожает процесс приложения для освобождения ресурсов в условиях нехватки памяти. В обычной ситуации onPause() и onStop() всегда вызываются перед onDestroy().
+ В штатном жизненном цикле `onPause()` вызывается перед `onStop()`, а затем может быть `onDestroy()`. Ситуация, когда `onDestroy()` вызывается без `onPause()`/`onStop()`, не является корректным сценарием жизненного цикла; чаще наоборот — `onDestroy()` может не быть вызван при убийстве процесса системой.
- #### Почему нам нужно вызывать `setContentView()` в `onCreate()` класса `Activity`?
setContentView() устанавливает макет пользовательского интерфейса для активности и должен быть вызван в onCreate(), чтобы до начала взаимодействия с пользователем активность имела загруженный и готовый интерфейс.
@@ -104,8 +103,8 @@
- Изменение конфигурации, не связанной с инициализацией UI, которая может быть выполнена в других методах жизненного цикла.
- #### Что такое `onSaveInstanceState()` и `onRestoreInstanceState()` в `Activity`?
- - `onSaveInstanceState()` - Этот метод используется для сохранения данных перед паузой `Activity`.
- - `onRestoreInstanceState()` - Этот метод используется для восстановления сохраненного состояния `Activity`, когда `Activity` пересоздается после уничтожения. Таким образом, `onRestoreInstanceState()` получает пакет, который содержит информацию о состоянии экземпляра.
+ - `onSaveInstanceState()` — вызывается, когда система может уничтожить Activity (например, при смене конфигурации). Используется для сохранения временного UI-состояния.
+ - `onRestoreInstanceState()` — вызывается после `onStart()`, когда Activity пересоздана и есть сохраненное состояние.
- #### Какие launch modes существуют для активити?
- **standard**: Запускает активити в новом экземпляре каждый раз.
@@ -119,7 +118,7 @@
- **onCreate()** - система вызывает этот метод, когда создает фрагмент. Создайте здесь компоненты, которые необходимы вне видимости пользователя.
- **onCreateView()** - вызывается для создания макета фрагмента. В этом методе вы должны создать и вернуть макет фрагмента.
- **onViewCreated()** - Вызывается сразу после onCreateView(), когда представление фрагмента уже создано. Это хорошее место для инициализации представлений.
- - **onActivityCreated()** - вызывается, когда активность, к которой прикреплен фрагмент, завершила свой метод onCreate().
+ - **onActivityCreated()** - (устаревшее, но иногда спрашивают) метод был deprecated; его роль обычно выполняется `onViewCreated()` и наблюдение за `viewLifecycleOwner`.
- **onStart()** - вызывается, когда фрагмент становится видимым.
- **onResume()** - вызывается, когда фрагмент получает фокус и может взаимодействовать с пользователем.
- **onPause()** - вызывается, когда пользователь теряет фокус на фрагменте, и можно сохранить изменения или обновления.
@@ -143,8 +142,8 @@
- Когда несколько представлений могут быть отображены бок о бок, как например `ViewPager`
- #### В чем разница между `FragmentPagerAdapter` и `FragmentStatePagerAdapter`?
- - `FragmentPagerAdapter`: Каждый `Fragment`, посещенный пользователем, будет храниться в памяти, но представление будет уничтожено. Когда страница снова посещается, то создается представление, а не экземпляр фрагмента.
- - `FragmentStatePagerAdapter`: Здесь экземпляр фрагмента будет уничтожен, когда он не виден пользователю, за исключением сохраненного состояния фрагмента.
+ - `FragmentPagerAdapter` и `FragmentStatePagerAdapter` — устаревшие адаптеры для ViewPager (устаревшее, но иногда спрашивают). Первый держит фрагменты в памяти, второй уничтожает их и сохраняет состояние.
+ - Современная альтернатива — `ViewPager2` с `FragmentStateAdapter`, который эффективно управляет состоянием и жизненным циклом фрагментов.
- #### В чем разница между добавлением/заменой фрагмента в backstack?
При добавлении фрагмента, он размещается поверх предыдущего, не удаляя его, в то время как замена удаляет текущий фрагмент и добавляет новый. Использование addToBackStack() позволяет возвращаться к предыдущему фрагменту с помощью кнопки "Назад".
@@ -152,9 +151,10 @@
- #### Как осуществляется коммуникация между двумя `Fragments`?
- Через ViewModel
- Через Activity
+ - Через `FragmentResultListener` (официальный API для передачи событий)
- #### Что такое retained `Fragment`?
- По умолчанию, `Fragments` уничтожаются и пересоздаются вместе с их родительскими `Activities` при изменении конфигурации. Вызов `setRetainInstance(true)` позволяет нам обойти этот цикл уничтожения и пересоздания, сигнализируя системе о сохранении текущего экземпляра фрагмента, когда `Activity` пересоздается.
+ Вызов `setRetainInstance(true)` (устаревшее, но иногда спрашивают) позволял сохранить экземпляр фрагмента при изменении конфигурации. Сейчас это API deprecated; рекомендуемая практика — использовать `ViewModel`/`SavedStateHandle` для сохранения данных при пересоздании UI.
- #### Какова цель `addToBackStack()` при выполнении транзакции фрагмента?
При вызове `addToBackStack()`, транзакция замены сохраняется в стеке возврата, так что пользователь может отменить транзакцию и вернуть предыдущий фрагмент, нажав кнопку Назад.
@@ -187,9 +187,9 @@
8. **onDraw(Canvas)**: onDraw() — это где вы определяете, как View должно отображать свое содержимое. Это может включать рисование форм, текста, изображений или других графических элементов. Этот метод переопределяется, когда вы создаете пользовательский View и хотите контролировать его визуальное представление.
-- #### В чем разница между методами invalidateLayout и requestLayout?
- - `invalidate()`: Вызывается, когда view должно быть перерисовано, но его размер и позиция не изменяются.
- - `requestLayout()`: Вызывается, когда view должно быть измерено и размещено заново, что может привести к изменению размеров и позиции как этого view, так и его потомков.
+- #### В чем разница между методами invalidate и requestLayout?
+ - `invalidate()`: Запрашивает перерисовку View, не меняя измерения и расположение.
+ - `requestLayout()`: Запрашивает повторное измерение и размещение View (и, при необходимости, его потомков), что может изменить размеры и позицию.
- #### Разница между `View.GONE` и `View.INVISIBLE`?
- **View.GONE** - этот параметр делает представление полностью невидимым и не занимает место в макете.
- **View.INVISIBLE** - представление остается невидимым, но все еще занимает место в макете.
@@ -202,28 +202,28 @@
- **ViewGroup** - ViewGroup это невидимый контейнер. Он содержит **View**s и **ViewGroup**s. Например, `LinearLayout` это ViewGroup, который содержит `Button`(View), и другие компоновки также. ViewGroup является базовым классом для компоновок.
- #### Что такое Canvas?
- **Canvas** — это одна из основных функций встроенного в Android фреймворка графического интерфейса, которая позволяет создавать разнообразные пользовательские интерфейсы и реализовывать сложную графику. С помощью этого инструмента разработчики могут реализовывать различные возможности, такие как рисование, анимация и обработка событий.
+ **Canvas** — это объект, через который View рисует своё содержимое в методе `onDraw(Canvas)`. Canvas предоставляет API для рисования текста, линий, фигур, изображений и т. п. с помощью `Paint`.
- #### Что такое SurfaceView?
- **SurfaceView** — это подкласс View, который предоставляет отдельный слой, на котором можно рисовать, не блокируя основной поток пользовательского интерфейса. Это полезно для рендеринга анимаций или видео, где требуется высокая производительность и меньшее взаимодействие с основным потоком UI.
+ **SurfaceView** — это View, которая создает отдельную поверхность (Surface), рисование на которой происходит в отдельном буфере и может выполняться из фонового потока. Это полезно для видео, игр и рендеринга с высокой частотой кадров. Для кейсов, где нужна трансформация и анимации на уровне View, чаще используют `TextureView`.
- #### Relative Layout против Linear Layout.
- - **Relative Layout** позволяет размещать виджеты относительно друг друга или относительно родительского контейнера.
- - **Linear Layout** размещает виджеты в линейной последовательности, горизонтально или вертикально.
+ - **RelativeLayout** позволяет размещать виджеты относительно друг друга или родительского контейнера (устаревшее, но иногда спрашивают).
+ - **LinearLayout** размещает виджеты линейно — горизонтально или вертикально.
+ - В современных UI чаще используют **ConstraintLayout** для уменьшения вложенности и гибкого позиционирования.
- #### Расскажите о Constraint Layout
- **Constraint Layout** — это гибкий и мощный макет в Android, который позволяет создавать сложные пользовательские интерфейсы без вложенных макетов. Он предоставляет широкие возможности для определения ограничений для позиционирования и размера виджетов, что облегчает создание адаптивных интерфейсов.
+ **ConstraintLayout** — это современный контейнер, позволяющий строить сложные и адаптивные UI с минимальной вложенностью. Он использует ограничения (constraints), цепочки, барьеры и гайдлайны для позиционирования и размеров.
- #### Знаете ли вы, что такое дерево View? Как можно оптимизировать его глубину? (ViewTreeObserver)
- **Дерево из View** — это иерархическая структура, которая представляет все виджеты (views) и макеты (layouts), составляющие пользовательский интерфейс в Android приложении. Оптимизировать глубину дерева View можно путем уменьшения количества вложенных макетов, использования **ConstraintLayout** для упрощения иерархии и избегания лишних макетов, которые не вносят вклад в пользовательский интерфейс. **ViewTreeObserver** может использоваться для прослушивания различных событий в дереве View, таких, как момент перед отрисовкой, что может быть полезно для дополнительных оптимизаций.
+ **Дерево View** — иерархия всех View/ ViewGroup на экране. Оптимизация глубины достигается уменьшением вложенности, объединением контейнеров, использованием **ConstraintLayout**, `merge` и устранением невидимых элементов. **ViewTreeObserver** позволяет слушать события дерева (например, `OnGlobalLayoutListener`, `OnPreDrawListener`) для точной настройки поведения после измерения/размещения.
#### *Отображение списков контента*
- #### Чем отличается `ListView` от `RecyclerView`?
- - **ListView** — это виджет для отображения списка данных в вертикальном порядке, который был частью Android с его первых версий. Он поддерживает базовую прокрутку и может отображать список, который подгружается в адаптер. Однако он имеет ограниченные возможности по настройке и не поддерживает разные типы элементов списка или сложные анимации.
-
- - **RecyclerView** — это более продвинутый и гибкий компонент для отображения списков данных, введенный в Android Lollipop (API уровня 21). Он поддерживает как вертикальную, так и горизонтальную прокрутку, разные типы элементов, сложные анимации, а также имеет более эффективное переиспользование элементов списка через механизм **ViewHolder**. RecyclerView также позволяет легко реализовать разные виды лэйаутов, такие как список, сетка и стаггеред грид.
+ - **ListView** — старый виджет списков (устаревшее, но иногда спрашивают). Поддерживает несколько типов элементов, но требует больше ручной настройки и хуже масштабируется по возможностям, чем RecyclerView.
+ - **RecyclerView** — современный компонент из AndroidX с гибкой архитектурой (LayoutManager, ItemAnimator, ItemDecoration). Поддерживает сложные анимации, разные типы элементов и эффективный рециклинг через **ViewHolder**.
- #### Как внутренне работает `RecyclerView`?
**RecyclerView** работает на основе адаптера, который управляет данными списка и связывает эти данные с видами, отображаемыми в RecyclerView. Ключевым компонентом является паттерн **ViewHolder**, который хранит ссылки на все подвиды каждого элемента списка для быстрого доступа без необходимости повторного поиска. При прокрутке списка RecyclerView переиспользует виды, которые вышли за пределы экрана, применяя к ним новые данные, что значительно повышает производительность и эффективность использования памяти.
@@ -243,7 +243,7 @@
**SnapHelper** — это класс помощник, предназначенный для вспомогательной привязки (snapping) элементов RecyclerView к определенной точке на экране, обычно в центре или краях экрана, когда прокрутка останавливается. Это удобно, например, для создания галерей или каруселей, где требуется, чтобы элементы выравнивались относительно определенных точек.
- #### Что такое DiffUtils?
- **DiffUtil** — это утилита, предоставляемая Android SDK, которая помогает вычислить разницу между двумя списками и выдать набор операций обновления, необходимых для преобразования одного списка в другой. Это может использоваться в адаптере RecyclerView для минимизации количества обновлений и повышения производительности, особенно когда изменения в данных минимальны. **DiffUtil** вычисляет минимальное количество изменений и автоматически обновляет список с анимациями, делая пользовательский интерфейс более плавным и отзывчивым.
+ **DiffUtil** — утилита из RecyclerView, которая вычисляет разницу между двумя списками и формирует минимальный набор операций обновления. Обычно используется в паре с `ListAdapter`/`AsyncListDiffer`, чтобы обновления списка были эффективными и анимации оставались плавными.
#### *Диалоги и Toast*
@@ -276,31 +276,43 @@
**BroadcastReceiver** — это компонент приложения, который позволяет реагировать на широковещательные сообщения от других приложений или от самой системы. Эти сообщения могут касаться различных событий, таких как изменение заряда батареи, получение SMS или изменение сетевого состояния.
- #### Что такое липкий `Intent` (`Sticky Intent`)?
- **Липкий Intent (Sticky Intent)** — это широковещательное сообщение, которое после отправки "застревает" в системе, позволяя новым подписчикам на BroadcastReceiver получить данные события даже после его завершения. Примером использования может быть запрос текущего состояния батареи. Следовательно, вы можете использовать это для определения состояния батареи без обязательной регистрации всех будущих изменений состояния батареи.
+ **Sticky Intent** — это широковещательное сообщение, которое остается в системе и может быть получено новыми подписчиками. Это API в основном устарело: большинство sticky broadcast-ов запрещены для сторонних приложений, исключения — системные (например, `ACTION_BATTERY_CHANGED`, который можно читать через `registerReceiver(null, filter)`).
- #### Опишите, как работают `Broadcasts` и `intents`, чтобы передавать сообщения по вашему приложению?
**Broadcasts** и **intents** позволяют компонентам приложения общаться между собой без необходимости напрямую связывать их код. **Intents** могут быть использованы для явного запуска компонентов внутри приложения или для неявного запроса действий от других приложений. **Broadcasts** позволяют отправлять широковещательные сообщения системе или приложениям, на которые подписаны **BroadcastReceivers**, реагирующие на определенные события или интенты.
+- #### Какие ограничения на неявные `BroadcastReceiver` в манифесте?
+ Начиная с Android 8.0, большинство неявных broadcast-ов нельзя регистрировать в манифесте. Исключения перечислены в документации. Обычно используют динамическую регистрацию или `WorkManager`.
+
- #### Что такое `PendingIntent`?
- **PendingIntent** — это токен, который вы передаете внешнему приложению (например, уведомлению, виджету), который позволяет этому приложению использовать разрешение вашего приложения для выполнения предопределенной операции. В основном, **PendingIntent** используется для уведомлений, чтобы открыть активность или выполнить сервис при нажатии на уведомление.
+ **PendingIntent** — это токен, который вы передаете внешнему приложению (например, уведомлению, виджету), чтобы оно выполнило действие от имени вашего приложения. Начиная с Android 12 необходимо явно указывать `FLAG_IMMUTABLE` или `FLAG_MUTABLE` в зависимости от того, требуется ли менять содержимое интента.
- #### Какие существуют различные типы `Broadcasts`?
-
+ - **Normal broadcasts** — доставляются асинхронно всем подписчикам.
+ - **Ordered broadcasts** — доставляются по очереди с возможностью приоритетов и прерывания.
+ - **Sticky broadcasts** — устаревшее, в основном запрещено для сторонних приложений.
+ - **Local broadcasts** — (устаревшее, но иногда спрашивают) `LocalBroadcastManager` из AndroidX deprecated; вместо него используют `Flow`, `LiveData`, `SharedFlow` или другие локальные шины событий.
#### *Services*
- #### Что такое `Service`?
- **Service** – это компонент приложения, который может выполнять длительные операции в фоновом режиме и не предоставляет пользовательского интерфейса. Другими словами, это способ выполнить некоторые действия в фоне, например, проигрывание музыки, загрузку файлов и т. д., без взаимодействия с пользовательским интерфейсом. Сервисы могут быть как связанными (bound), так и несвязанными. Связанный сервис предлагает клиент-серверный интерфейс, который позволяет компонентам (например, активности) взаимодействовать с сервисом, отправлять запросы, получать результаты через IPC (Межпроцессное взаимодействие). Несвязанный сервис обычно выполняется на заднем плане и не связан с каким-либо пользовательским интерфейсом или компонентом, который его запустил.
+ **Service** – это компонент приложения без UI, предназначенный для выполнения долгих задач. Методы сервиса по умолчанию вызываются в **главном потоке**, поэтому для тяжелой работы нужно создавать фоновые потоки. Сервисы бывают связаны (bound) и несвязаны (started). Связанный сервис предоставляет клиент-серверный интерфейс (включая IPC), несвязанный выполняется в фоне и управляется `startService()`/`stopSelf()`.
- #### `Service` vs `IntentService`
-
+ **IntentService** — специализированный сервис, который обрабатывал входящие интенты последовательно в фоновом потоке и автоматически завершался. Он объявлен deprecated; современная альтернатива — `WorkManager`/`JobIntentService` (устаревшее, но иногда спрашивают) или собственный `Service` с корутинами/Executors.
+ **Service** — более общий компонент, который нужно самостоятельно управлять (потоки, жизненный цикл, остановка).
- #### Что такое сервис переднего плана (`Foreground Service`)?
**Сервис переднего плана (Foreground Service)** – это сервис, который выполняется на переднем плане и обязательно показывает уведомление в строке состояния. Это уведомление информирует пользователя о том, что приложение выполняет некоторую задачу, которая требует внимания пользователя. Сервисы переднего плана обычно используются для задач, которые непосредственно влияют на работу пользователя с устройством, например, для проигрывания аудио или для выполнения активной задачи, такой как навигация. Использование сервиса переднего плана помогает обеспечить, что система не остановит ваше приложение, пока выполняется важная задача.
+ Начиная с Android 8.0 сервис должен быть запущен через `startForegroundService()`, а `startForeground()` нужно вызвать в течение 5 секунд. С Android 10+ есть типы foreground-сервисов (location, mediaPlayback и т. п.), которые нужно указать в манифесте и соблюдать ограничения.
+
+- #### Какие ограничения на фоновые сервисы появились в Android 8.0+?
+ Android 8.0 ввел **background execution limits**: нельзя свободно запускать фоновые сервисы, если приложение в фоне. Для долгих задач нужно использовать foreground service или `WorkManager`. Также ограничены неявные broadcast-ы и фоновые location updates.
- #### Что такое `JobScheduler`?
**JobScheduler** – это системный сервис, доступный начиная с Android 5.0 (API уровень 21), который позволяет разработчикам планировать различные виды задач (работы) для выполнения в определенных условиях. С помощью JobScheduler можно управлять выполнением задач в зависимости от таких условий, как состояние сети, заряд батареи и другие. Это позволяет приложениям выполнять фоновые задачи более эффективно, экономя заряд батареи и ресурсы системы. Работы, запланированные с помощью JobScheduler, могут выполняться даже после перезагрузки устройства.
+ На практике для совместимости с более старыми версиями и простой интеграции чаще используют **WorkManager**, который внутри использует JobScheduler/AlarmManager/Firebase JobDispatcher.
#### *Межпроцессорное взаимодействие (IPC)*
@@ -324,9 +336,11 @@
- #### Что можно использовать для фоновой обработки в `Android`?
* **Сервисы (Services)**: Для выполнения длительных задач на фоне.
- * **JobScheduler**: Для планирования задач, которые должны выполняться при определенных условиях.
- * **WorkManager**: Для гарантированного выполнения фоновых задач и работы с ограничениями, накладываемыми системой на фоновую работу.
- * **IntentService**: Для обработки асинхронных запросов через интенты на фоне.
+ * **Foreground Service**: Для долгих задач, которые должны быть видимы пользователю (уведомление обязательно).
+ * **JobScheduler**: Для задач при определенных условиях (API 21+).
+ * **WorkManager**: Для гарантированного выполнения фоновых задач с ограничениями и совместимостью.
+ * **AlarmManager**: Для точных будильников (например, напоминания), но с ограничениями по энергопотреблению.
+ * **IntentService/JobIntentService** (устаревшее, но иногда спрашивают): старые способы обработки интентов в фоне.
- #### Что такое `ContentProvider` и для чего он обычно используется?
**ContentProvider** – это компонент приложения, который позволяет делиться данными между разными приложениями. Он предоставляет структурированный интерфейс к данным, хранящимся в файловой системе, базе данных SQLite, вебе или любом другом постоянном хранилище данных, которым управляет приложение. **ContentProvider** чаще всего используется для доступа к данным в разных приложениях, например, для доступа к контактам, календарю и другим личным данным пользователя.
@@ -343,11 +357,11 @@
* **Kotlin Coroutines**: В Kotlin для параллельного выполнения задач и получения результатов можно использовать корутины с применением функций **async** и **await** внутри **CoroutineScope**. Это позволяет писать асинхронный код, который выглядит как синхронный, и легко получать результаты выполнения задач.
- #### Что такое ANR? Как можно предотвратить ANR?
- **ANR (Application Not Responding)** – это ошибка, которая происходит, когда приложение не отвечает на ввод пользователя в течение 5 секунд. Чаще всего ANR возникает, если приложение выполняет длительные операции в главном потоке (UI thread).
+ **ANR (Application Not Responding)** – это ситуация, когда приложение слишком долго не отвечает. Типичные тайм-ауты: около 5 секунд для обработки ввода, около 10 секунд для `BroadcastReceiver` и около 20 секунд для `Service` (в разных версиях Android возможны отличия; если важно, уточняйте по текущей документации).
_**Предотвращение ANR:**_
* **Использование фоновых потоков**: Выполняйте длительные операции (например, сетевые запросы, обращение к базе данных) в фоновых потоках, не блокируя главный поток.
- * **AsyncTask** (до API уровня 30): AsyncTask позволял выполнять асинхронные операции на фоне, но был объявлен устаревшим. Вместо него рекомендуется использовать другие механизмы асинхронной работы.
+ * **AsyncTask** (устаревшее, но иногда спрашивают): был объявлен deprecated, вместо него используют корутины/Executors/WorkManager.
* **Использование WorkManager, JobScheduler**: Эти компоненты предназначены для выполнения фоновых задач, учитывая ограничения системы и оптимизируя использование ресурсов.
- #### Что такое `AsyncTask` (Устарел в API уровня 30)?
@@ -371,26 +385,37 @@
#### *Асинхронность*
- #### Как выполнять асинхронные операции в Android?
- Можно использовать несколько подходов, включая AsyncTask, Loader, IntentService, HandlerThread. С появлением Kotlin в Android разработке стали популярны корутины для управления асинхронными задачами благодаря их эффективности и простоте использования.
+ Можно использовать несколько подходов, включая корутины, Executors, `HandlerThread`, `WorkManager`. `AsyncTask`, `Loader` и `IntentService` — устаревшие, но иногда спрашивают.
- #### Почему в Android возникла необходимость асинхронности? Почему мы не можем выполнять все в одном потоке?
Основной UI поток (Main Thread) отвечает за обработку пользовательского интерфейса, включая отрисовку элементов на экране и обработку пользовательских взаимодействий. Выполнение длительных операций в главном потоке приводит к "зависанию" приложения и плохому пользовательскому опыту. Асинхронность позволяет выполнять тяжелые задачи в фоновых потоках, не блокируя UI поток.
- #### Какие подходы существуют в Android для обеспечения асинхронности?
- - **AsyncTask** и **Loader**: Предоставляют фреймворки для выполнения фоновых задач с возможностью обновления UI по завершении.
- - **IntentService**: Позволяет выполнить операции в фоновом сервисе.
+ - **AsyncTask/Loader/IntentService**: устаревшие механизмы для выполнения фоновых задач.
- **Handler** и **Looper**: Управление потоками с помощью сообщений и выполнение кода в других потоках.
- **Kotlin Coroutines**: Современный и эффективный способ для асинхронного программирования, позволяет выполнять асинхронные задачи с минимальными накладными расходами и упрощенным кодом.
- **RxJava**: Библиотека для композиции асинхронного и событийно-ориентированного программирования с использованием наблюдаемых последовательностей.
+ - **WorkManager/JobScheduler**: Для гарантированных или отложенных фоновых задач с учетом ограничений системы.
#### *Работа с мультимедиа контентом*
- #### Как вы обрабатываете изображения в формате `bitmap` в `Android`, так как они занимают слишком много памяти?
+ - Использовать `BitmapFactory.Options` с `inJustDecodeBounds`, чтобы получить размеры и рассчитать `inSampleSize`.
+ - Подбирать конфигурацию (`ARGB_8888` vs `RGB_565`) в зависимости от качества и памяти.
+ - Избегать декодирования на UI потоке; использовать фоновые потоки или библиотеки (Glide/Coil).
+ - Использовать кэширование и пуллинг (`inBitmap`) через image-loading библиотеки.
+ - Для API 28+ использовать `ImageDecoder`, который корректно учитывает цветовые профили и HDR.
- #### Расскажите о пуле `bitmap`.
+ Пул битмапов — механизм повторного использования выделенной памяти под `Bitmap`, чтобы сократить аллокации и нагрузку на GC. На практике применяется через библиотеки Glide/Coil, которые управляют пулом и кэшами автоматически.
#### *Сохранение данных*
- #### Jetpack DataStore Preferences
+ **DataStore** — современная замена `SharedPreferences`.
+ Варианты:
+ - **Preferences DataStore** — ключ-значение без схемы.
+ - **Proto DataStore** — типизированный формат на основе Protobuf со схемой.
+ DataStore работает асинхронно (корутины/Flow) и избегает гонок записи.
- #### Как сохранить данные в приложении `Android`?
@@ -416,86 +441,133 @@
- В целом, использование Parcelable рекомендуется для передачи данных между компонентами Android, особенно если требуется высокая производительность.
- #### Что такое ORM? Как это работает?
+ **ORM (Object-Relational Mapping)** — подход, который сопоставляет объекты языка с таблицами БД и автоматически генерирует SQL-операции. В Android типичный ORM — Room, который использует аннотации и генерирует код для маппинга сущностей.
- #### Как сохранить состояние `Activity` во время поворота экрана?
+ - `onSaveInstanceState()` и восстановление в `onCreate()`/`onRestoreInstanceState()`.
+ - `ViewModel` для данных, переживающих конфигурационные изменения.
+ - `SavedStateHandle` для восстановления после уничтожения процесса.
- #### Какие разные способы хранения данных в вашем приложении `Android`?
+ - **DataStore/SharedPreferences** — настройки и простые данные.
+ - **Room/SQLite** — структурированные данные.
+ - **Файлы** (internal/external storage) — медиа и большие объекты.
+ - **Кэш** (memory/disk) — временные данные.
+ - **Шифрованные хранилища** — для чувствительных данных.
- #### Объясните Scoped Storage в `Android`.
+ **Scoped Storage** (Android 10+) ограничивает прямой доступ к общей внешней памяти: приложение видит свои директории, а доступ к общим файлам осуществляется через `MediaStore` или `Storage Access Framework`. Полный доступ возможен только с `MANAGE_EXTERNAL_STORAGE` (ограниченное и нежелательное разрешение).
- #### Как зашифровать данные в `Android`?
+ - Использовать **Jetpack Security**: `EncryptedSharedPreferences`, `EncryptedFile`.
+ - Хранить ключи в **Android Keystore**.
+ - Для БД — SQLCipher или шифрование на уровне поля.
- #### Что такое `commit()` и `apply()` в `SharedPreferences`?
+ `commit()` синхронно записывает данные и возвращает `boolean` результата.
+ `apply()` пишет асинхронно без возврата результата и не блокирует UI поток.
#### *Look and Feel*
- #### Что такое `Spannable`?
+ **Spannable** — интерфейс для текста, позволяющий применять стили и действия к частям строки (цвет, размер, кликабельность и т. д.).
- #### Что такое `SpannableString`?
+ **SpannableString** — реализация `Spannable`, которая хранит строку и набор спанов для ее частей.
- #### Какие лучшие практики использования текста в `Android`?
+ - Использовать `sp` для размеров шрифта, `dp` для отступов.
+ - Хранить строки в `strings.xml` и использовать локализацию.
+ - Следить за доступностью: контраст, `contentDescription`, масштабирование шрифтов.
+ - Использовать `fontFamily`/`font` ресурсы и избегать хардкода.
- #### Как реализовать темную тему в любом приложении?
+ - Использовать `Theme.Material3`/`MaterialComponents` с `DayNight`.
+ - Создать ресурсы в `values-night/` для цветов/тем.
+ - Управлять режимом через `AppCompatDelegate.setDefaultNightMode(...)`.
#### *Оптимизация памяти*
- #### Что такое метод `onTrimMemory()`?
+ `onTrimMemory(level)` — колбэк, через который система уведомляет приложение о нехватке памяти. Уровни показывают серьезность (например, `TRIM_MEMORY_UI_HIDDEN`, `TRIM_MEMORY_RUNNING_LOW`), и приложение должно освобождать кэш или ресурсы.
- #### Как идентифицировать и устранить проблемы с OutOfMemory?
+ - Использовать Android Studio Memory Profiler и анализ heap dump.
+ - Проверять крупные битмапы, утечки контекстов и кэши.
+ - Оптимизировать изображения (inSampleSize, WebP/AVIF, lazy-loading).
+ - Снижать удержание объектов (например, через WeakReference) и ограничивать кэши.
- #### Как найти утечки памяти в приложениях `Android`?
+ - Использовать **LeakCanary** для автоматического обнаружения утечек.
+ - Анализировать heap dump через Memory Profiler.
+ - Проверять статические ссылки на контекст/Activity и незакрытые подписки.
#### *Оптимизация времени работы батареи*
- #### Как снизить потребление батареи в приложении `Android`?
+ - Батчить фоновые задачи (WorkManager/JobScheduler).
+ - Минимизировать частые `wake locks`, GPS и сетевые запросы.
+ - Использовать `FusedLocationProvider` с корректными приоритетами.
+ - Учитывать ограничения Doze/App Standby и использовать push/FCM при необходимости.
- #### Что такое Doze? Что насчет App Standby?
- **Doze** — это режим энергосбережения, добавленный в Android 6.0 (Marshmallow), который снижает потребление батареи, ограничивая фоновую активность приложений, когда устройство не используется в течение длительного времени.
- **App Standby** — это функция, также введенная в Android 6.0 (Marshmallow), которая ограничивает фоновую активность приложений, если пользователь не активно использует эти приложения.
+ - Начиная с Android 9 появились **App Standby Buckets**, которые добавляют уровни ограничений в зависимости от активности пользователя.
- #### Что такое перерисовка?
**Перерисовка (или re-draw)** — это процесс, при котором элементы интерфейса пользователя перерисовываются на экране. Это может происходить при изменении данных, которые отображаются в элементе пользовательского интерфейса, или при изменении состояния видимости элемента. Частые перерисовки могут негативно сказаться на производительности и потреблении батареи.
+ Избыточная перерисовка приводит к **overdraw** — повторному рисованию одних и тех же пикселей.
#### *Поддержка разных экранов*
- #### Как вы поддерживаете различные типы разрешений экранов?
+ - Использовать `dp`/`sp`, `ConstraintLayout`, адаптивные размеры.
+ - Подготавливать ресурсы с квалификаторами (`sw600dp`, `land`, `xxhdpi`).
+ - Тестировать на разных размерах и использовать `WindowSizeClass` (Compose) или `Configuration`.
#### *Разрешения*
- #### Какие разные уровни защиты в разрешениях?
+ - **Normal** — выдаются автоматически.
+ - **Dangerous** — требуют запроса во время выполнения (runtime permissions).
+ - **Signature** — доступны только приложениям с одинаковой подписью.
+ - **Special/App ops** — особые разрешения (например, `SYSTEM_ALERT_WINDOW`, `MANAGE_EXTERNAL_STORAGE`).
#### *Native программирование*
- #### Что такое NDK и почему он полезен?
+ **NDK (Native Development Kit)** позволяет писать части приложения на C/C++ для производительности, повторного использования кода или работы с низкоуровневыми библиотеками. Использование NDK оправдано для CPU-интенсивных задач, криптографии, медиа-обработки и игр.
- #### Что такое renderscript?
+ **RenderScript** — фреймворк для вычислений на GPU/CPU, который был deprecated (устаревшее, но иногда спрашивают). Рекомендованная замена — `RenderScript Intrinsics Replacement Toolkit` или вычисления через Vulkan/OpenGL/NEON.
#### *Внутренности Системы Android*
- #### Что такое Android Runtime?
- **Android Runtime (ART)** — это среда выполнения приложений для операционной системы Android, которая заменила Dalvik в качестве основной среды выполнения с Android версии 5.0 (Lollipop). ART оптимизирует приложения при их установке, предварительно компилируя их в машинный код, что улучшает производительность и эффективность работы приложений по сравнению с предыдущей системой Dalvik, которая компилировала код во время выполнения приложения (Just-In-Time, JIT компиляция).
+ **Android Runtime (ART)** — среда выполнения приложений Android, которая заменила Dalvik с Android 5.0. Современный ART использует комбинированный подход AOT + JIT с профилированием (profile-guided compilation), что ускоряет запуск и снижает объем заранее скомпилированного кода.
- #### Dalvik, ART, JIT и AOT в `Android`
- - **Dalvik** — это виртуальная машина, используемая в Android до версии 5.0 (Lollipop), которая использовала **JIT (Just-In-Time)** компиляцию, что означает компиляцию кода приложения в момент его выполнения.
- - **ART (Android Runtime)** — среда выполнения, которая использует подход **AOT (Ahead-Of-Time)** компиляции, предварительно компилируя приложения в машинный код при их установке, что повышает производительность.
+ - **Dalvik** — виртуальная машина до Android 5.0 (устаревшее, но иногда спрашивают), использовала в основном **JIT** компиляцию.
+ - **ART (Android Runtime)** — современная среда выполнения, сочетающая **AOT** и **JIT** с профилированием.
- **JIT (Just-In-Time)** — метод компиляции, при котором код компилируется в момент его выполнения, а не заранее.
- **AOT (Ahead-Of-Time)** — метод компиляции, при котором код приложения компилируется в машинный код заранее, при установке приложения, что ускоряет его запуск и работу.
- #### В чем различия между Dalvik и ART?
- Основное различие между **Dalvik** и **ART** заключается в методе компиляции. **Dalvik** использовал **JIT** компиляцию, компилируя код во время его выполнения, что могло замедлять запуск приложений. **ART** использует **AOT** компиляцию, компилируя приложения заранее при их установке, что ускоряет их запуск и улучшает производительность. **ART** также обеспечивает лучшую управляемость памятью и более эффективное выполнение приложений.
+ **Dalvik** (устаревшее, но иногда спрашивают) использовал в основном JIT-компиляцию. **ART** использует AOT + JIT с профилированием, что дает более быстрый старт, лучшую производительность и управление памятью.
- #### Что такое DEX?
**DEX (Dalvik Executable)** — это формат исполняемых файлов, используемых в Android. Это упакованный файл, содержащий скомпилированный код, который может быть исполнен виртуальной машиной **Dalvik** или **ART**. Файлы **DEX** оптимизированы для минимизации потребления памяти и улучшения производительности на устройствах Android.
@@ -553,6 +625,7 @@
5. **Пользовательская обратная связь**: Отслеживайте отзывы пользователей для выявления сбоев, которые не были обнаружены во время тестирования.
- #### Объясните как работает система уведомлений `Android`.
+ Уведомления публикуются через `NotificationManager`. Начиная с Android 8.0 требуется создавать **NotificationChannel** с уровнем важности. Уведомление строится через `NotificationCompat.Builder`, может содержать `PendingIntent` для действий. Для foreground-сервисов уведомление обязательно. С Android 13 требуется runtime-разрешение `POST_NOTIFICATIONS` для показа уведомлений.
- #### В чем разница между `Serializable` и `Parcelable`? Какой подход лучше в `Android`?
@@ -561,21 +634,31 @@
Хотя Serializable проще в реализации, Parcelable является предпочтительным выбором для Android из-за его высокой производительности, особенно при передаче сложных объектов между компонентами.
- #### Что такое AAPT?
+ **AAPT/AAPT2 (Android Asset Packaging Tool)** — инструмент сборки, который обрабатывает ресурсы (R.java/R.kt), упаковывает их в APK/AAB и выполняет оптимизацию ресурсов. В современных сборках используется AAPT2.
- #### FlatBuffers vs JSON.
+ **FlatBuffers** — бинарный формат с возможностью zero-copy доступа, меньшим размером и высокой скоростью, но сложнее в отладке и требует схемы.
+ **JSON** — текстовый формат, удобный для отладки и совместимости, но более тяжелый по размеру и требует парсинга.
- #### `HashMap`, `ArrayMap` и `SparseArray`
+ - **HashMap** — стандартная структура Java, универсальна, но имеет накладные расходы на объекты.
+ - **ArrayMap** — Android-оптимизированная карта для небольших наборов данных, экономит память за счет массивов.
+ - **SparseArray** — специализированная структура для `int` ключей, экономит память и избегает boxing.
- #### Что такое Аннотации?
+ Аннотации — метаданные, которые добавляются к коду и могут использоваться компилятором или в рантайме (например, `@Nullable`, `@Retention`, `@Target`).
- #### Как создать пользовательскую Аннотацию?
+ Создать `annotation class` в Kotlin или `@interface` в Java, указать `@Retention` (SOURCE/BINARY/RUNTIME) и `@Target` (классы, функции, параметры и т. д.).
- #### Что такое Support Library? Почему она была введена?
+ **Support Library** — устаревший набор библиотек, предоставлявший совместимость с более старыми версиями Android. Сейчас заменен на **AndroidX** (устаревшее, но иногда спрашивают).
-- #### Что такое Data Binding в `Android`?
\ No newline at end of file
+- #### Что такое Data Binding в `Android`?
+ **Data Binding** — библиотека, позволяющая связывать данные и UI напрямую в XML с выражениями. Она поддерживает двустороннее связывание и уменьшает количество boilerplate. Для более простого доступа к View чаще используют **View Binding** (без выражений и двусторонних связей).