Прямые ссылки на публичные уроки для быстрого старта и стабильной индексации lesson-страниц.
Поговорим про основные компоненты Android. У начинающих разработчиков возникнет резонный вопрос: "А зачем мне эта информация и что это вообще за компоненты".
Эти компоненты являются основой любого приложения. Без их понимания вы будете двигаться в разработке на ощупь, а некоторые функции и вовсе не сможете реализовать.
При изучении любой технологии полезно иметь общую картину. Например, чтобы лучше понять Activity, нужно понимать его место среди других компонентов в системе.
В текущем уроке — обзорная информация по компонентам без лишней технической детализации. Этого достаточно, чтобы начать понимать их роль и ответить на вопрос об их перечислении — один из самых распространённых на собеседовании.
Приложение не может напрямую работать с операционной системой Android. Нельзя просто так отобразить интерфейс на устройстве, залезть в телефонный справочник или включить камеру.
Чтобы взаимодействовать с OS и предоставлять пользователю функции, разработчики используют базовые компоненты Android. Эти компоненты выступают как мосты между приложением и OS Android, и каждый из них может служить точкой входа в приложение.
Существует 4 базовых компонента: Activity, Service, Content Provider, Broadcast Receiver.
Activity представляет собой экран (UI – User Interface) — то, что пользователь видит и с чем взаимодействует.
Activity чаще всего используется как основная точка входа в приложение. Пользователь нажимает на иконку приложения — запускается Activity, указанная в манифесте. В нашем случае это MainActivity.
Даже если в приложении несколько Activity, система запустит именно тот, что прописан с тегом <intent-filter>, содержащим action MAIN и category LAUNCHER. Таким образом мы явно указываем стартовый экран. Про интенты и интент-фильтры подробнее поговорим в уроке, посвящённом компоненту Activity.
Service — компонент Android, отвечающий за выполнение долгих фоновых операций, которые как правило не требуют взаимодействия с пользователем.
Например, когда вы включаете музыку, блокируете экран и переключаетесь на другие приложения — музыка продолжает играть. Именно Service выполняет работу в фоне, не будучи привязанным к интерфейсу.
Сервис создаётся как обычный класс, наследующийся от класса Service. При этом обязательно нужно реализовать метод onBind().
Метод служит для создания связи с другими компонентами, например, с Activity — чтобы напрямую получать данные или управлять методами сервиса в режиме реального времени. Если привязка не требуется, метод должен возвращать null.
class MusicService : Service() { override fun onBind(p0: Intent?): IBinder? { return null } }
У Service есть ряд необязательных методов, доступных через меню Generate (cmd/ctrl + N → Override methods). Для примера рассмотрим три из них: onStart(), onStartCommand() и onDestroy().
onStart() вызывается системой при создании сервиса, до выполнения команд из onStartCommand() и до привязки через onBind(). Здесь инициализируются ресурсы: сетевые соединения, подключения к базам данных, обработка пользовательских запросов.
onStartCommand() вызывается каждый раз, когда компонент (например, Activity) запускает сервис через startService(). Здесь прописывается основная кастомная логика работы сервиса.
onDestroy() вызывается при уничтожении сервиса — идеальное место для очистки ресурсов: закрытия потоков данных, остановки музыки. Это последний метод, который вызывает система перед уничтожением сервиса.
class MusicService : Service() { override fun onBind(p0: Intent?): IBinder? { return null } override fun onStart(intent: Intent?, startId: Int) { super.onStart(intent, startId) } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { return super.onStartCommand(intent, flags, startId) } override fun onDestroy() { super.onDestroy() } }
После создания сервиса не забудьте зарегистрировать его в манифесте.
На собеседовании часто спрашивают про виды сервисов. В Android различают 3 основных типа. Первые два — Unbound (не зависят от привязки):
Content Provider — компонент, управляющий доступом к данным приложения и предоставляющий их другим приложениям. Его можно сравнить с почтовым ящиком: одни приложения кладут данные (контакты, фотографии), другие берут их оттуда, зная адрес.
Ключевое преимущество — стандартизация доступа к данным. Не нужно знать, как данные хранятся (база данных, файл и т.д.) — Content Provider абстрагирует эти детали через CRUD-операции (Create, Read, Update, Delete), реализуемые через переопределённые методы.
Для создания провайдера нужно унаследоваться от ContentProvider() и реализовать 6 обязательных методов:
class ContactsProvider : ContentProvider() { override fun onCreate(): Boolean { TODO("Not yet implemented") } override fun query( p0: Uri, p1: Array<out String>?, p2: String?, p3: Array<out String>?, p4: String? ): Cursor? { TODO("Not yet implemented") } override fun getType(p0: Uri): String? { TODO("Not yet implemented") } override fun insert(p0: Uri, p1: ContentValues?): Uri? { TODO("Not yet implemented") } override fun delete(p0: Uri, p1: String?, p2: Array<out String>?): Int { TODO("Not yet implemented") } override fun update(p0: Uri, p1: ContentValues?, p2: String?, p3: Array<out String>?): Int { TODO("Not yet implemented") } }
Назначение методов:
onCreate(): инициализирует провайдер — настройка БД или других ресурсов. Возвращает true при успешном создании.query(Uri, ...): выполняет запросы к данным. URI (Uniform Resource Identifier) — адрес для идентификации ресурса на устройстве или в сети.getType(Uri): указывает тип данных, которые возвращает URI, чтобы другие приложения могли правильно их обработать.insert(Uri, ContentValues?): вставляет новые данные в провайдер. Возвращает URI новой записи.delete(Uri, ...): удаляет данные по URI. Возвращает количество удалённых записей.update(Uri, ContentValues?, ...): обновляет существующие данные. Возвращает количество обновлённых записей.Broadcast Receiver — приёмник событий системы или других приложений. Его задача: ожидать сигнал, поймать его, обработать и запустить соответствующее действие в приложении.
Пример: в Telegram вы видите сообщение "У собеседника низкий заряд батареи". На устройстве собеседника Broadcast Receiver перехватил системное событие о низком заряде, обработал его и передал информацию приложению.
В коде ресивер создаётся наследованием от BroadcastReceiver с реализацией метода onReceive — он вызывается при получении ожидаемого события:
class BatteryLevelReceiver : BroadcastReceiver() { override fun onReceive(p0: Context?, p1: Intent?) { TODO("Not yet implemented") } }
Для работы компонент нужно зарегистрировать в OS. Есть два способа:
Статический — регистрация в AndroidManifest с указанием интент-фильтра, определяющего отслеживаемое событие:
<receiver android:name=".BatteryLevelReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BATTERY_LOW" /> </intent-filter> </receiver>
Интенты — механизм взаимодействия между компонентами, описывающий намерение что-то сделать. Интент-фильтры определяют, какие интенты может обрабатывать компонент. Подробнее о них — в следующих уроках в рамках работы с Activity.
Динамический — регистрация ресивера и интент-фильтров программно в коде, например, в Activity.
Это фундаментальные строительные блоки, на которых строится любой Android-проект. Использовать все компоненты одновременно не обязательно — всё зависит от функционала приложения.
Важно понимать: эти компоненты мы не создаём самостоятельно через new. Мы объявляем их в манифесте и просим систему создать их за нас. А для управления ими добавляем специфичную логику, реализуя собственные классы и переопределяя методы, унаследованные от выбранных компонентов.
Именно поэтому они называются "основные компоненты операционной системы Android" — как бы принадлежащие самой системе.