Created by AIImproved by people

Riqli · living documents · updated continuously

Where AI knowledge meets human practice.

Share with friends
image

Advanced Android

sections

Введение в многопоточность в Android

contents

Каждое Android-приложение имеет main thread (UI thread), который отвечает за обработку пользовательского ввода и отрисовку интерфейса. Выполнение тяжелых операций на этом потоке вызывает Application Not Responding (ANR).

contents

Для создания фонового потока можно использовать Thread с Runnable или наследование Thread с переопределением run(). Однако создание потока на каждую операцию неэффективно — лучше использовать пул потоков или HandlerThread.

sections

Коммуникация между потоками: Handler, Looper, MessageQueue

contents

Handler позволяет отправлять и обрабатывать Message и Runnable, связанные с MessageQueue конкретного потока. Looper — это бесконечный цикл, который извлекает сообщения из очереди и передает их Handler'у.

sections

Сервисы: подробный жизненный цикл и процессы

contents

Процесс в Android — это контейнер, в котором выполняются потоки. Приложение по умолчанию запускается в одном процессе. Процессы имеют иерархию важности: Foreground > Visible > Service > Background > Empty.

contents

Можно указать, чтобы компонент (Activity, Service) работал в отдельном процессе, добавив атрибут android:process в манифест. Однако многопроцессность усложняет коммуникацию: вместо прямых вызовов методов приходится использовать AIDL или Messenger.

sections

Foreground Services и Notifications

contents

Foreground Service — это сервис, который пользователь активно осознает (например, музыкальный плеер). Такой сервис должен отображать постоянное уведомление в панели (Notification), и система с меньшей вероятностью его убьет.

sections

IntentService: упрощенная обработка фоновых задач

contents

IntentService — это базовый класс, который автоматически создает фоновый поток (HandlerThread) и очередь для обработки Intent. После обработки всех задач сервис останавливается сам.

sections

Broadcast Receivers: системные и кастомные

contents

BroadcastReceiver позволяет приложению реагировать на системные события (смена сети, заряд батареи) и кастомные события от других приложений. Метод onReceive() должен выполняться быстро (до 10 секунд), иначе система сочтет ресивер зависшим.

sections

LocalBroadcastManager и безопасные внутриприкладные события

contents

LocalBroadcastManager — это утилита для отправки/приема Broadcast Intents в пределах одного приложения. Данные не покидают ваше приложение, что безопаснее и эффективнее глобальных системных broadcast'ов.

sections

Уведомления (Notifications): PendingIntent и действия

contents

PendingIntent — это токен, который позволяет другому приложению (например, системе) выполнить действие от имени вашего приложения. Используется в уведомлениях, виджетах и AlarmManager.

contents

Для создания Notification используется Notification.Builder, который требует иконку (setSmallIcon()), заголовок (setContentTitle()) и текст (setContentText()). Начиная с Android 8, необходимо указать NotificationChannel.

sections

Виджеты: List Widget и RemoteViewsFactory

contents

Для создания списка в виджете нужно использовать RemoteViewsService и RemoteViewsFactory. Обычный ListAdapter не подходит, так как виджет работает в другом процессе.

contents

Чтобы обрабатывать клики на элементах списка в виджете, нужно вызвать setOnClickFillInIntent() для RemoteViews, а не setOnClickPendingIntent. Это позволяет заполнить Intent уникальными данными (позиция, ID) для каждого элемента.

sections

Kotlin: свойства, нул-безопасность и области видимости

contents

Kotlin устраняет NullPointerException на уровне типа: типы по умолчанию non-null. Для nullable переменных нужно использовать оператор ?. (safe call) или !! (force unwrap) с осторожностью.

sections

Тестирование: покрытие граничных случаев и исключений

contents

При тестировании важно проверять не только happy path, но и граничные условия: null, пустые коллекции, максимальные/минимальные значения, неправильный формат данных. Это помогает отловить скрытые баги.

sections

Bound Services: двойная привязка и Messenger

contents

Bound service позволяет клиентам взаимодействовать с сервисом через интерфейс IBinder. Если сервис одновременно является started и bound, он не будет уничтожен, пока не выполнит свою работу и не отвяжутся все клиенты.

contents

Для межпроцессного взаимодействия (IPC) с сервисом вместо прямых вызовов методов нужно использовать Messenger. Клиент отправляет Message объект, а сервис отвечает через replyTo.

sections

Паттерн Model-View-Presenter (MVP) для тестирования

contents

Паттерн MVP отделяет логику (Presenter) от Android-фреймворка (View — Activity/Fragment). Это позволяет unit-тестировать презентер без эмулятора, используя моки для интерфейса View.

sections

Robolectric: теневая реализация Android SDK

contents

Robolectric — это фреймворк, который подменяет стандартные Android-классы на свои Shadow-реализации во время выполнения тестов на JVM, позволяя тестировать код, зависимый от фреймворка.

sections

Тестирование пользовательского интерфейса (UI Testing)

contents

UI-тесты (инструментальные) запускаются на реальном устройстве или эмуляторе. Фреймворк Espresso автоматически синхронизируется с потоком UI, избавляя от ручных задержек (Thread.sleep()).

sections

Композиция против наследования при тестировании

contents

Принцип композиции (has-a) предпочтительнее наследования (is-a) для тестируемого кода. Это позволяет легко подменять зависимости на mock-объекты и соблюдать Single Responsibility Principle.


questions

Что произойдет, если выполнить сетевой запрос на main thread в Android?

answersCorrect

Приложение выбросит исключение NetworkOnMainThreadException (на API > 3.0) или зависнет с ошибкой ANR.

explanations

Android запрещает блокирующие сетевые операции на UI thread, чтобы гарантировать отзывчивость интерфейса. Для загрузки данных необходимо создавать фоновые потоки (Thread, AsyncTask, RxJava, Coroutines) или использовать сервисы.

answersWrong

Запрос выполнится, но медленно

answersWrong

Приложение автоматически создаст фоновый поток


questions

В чем разница между передачей Runnable в конструктор Thread и созданием класса, наследующего Thread?

answersCorrect

Оба способа позволяют выполнить код в новом потоке, но наследование Thread используется реже, так как нарушает принцип композиции над наследованием.

explanations

Использование Runnable является более гибким: вы можете запустить один и тот же Runnable в разных потоках или использовать в ThreadPoolExecutor. Наследование Thread связывает код выполнения с самим потоком, что уменьшает возможность повторного использования.

answersWrong

Runnable нельзя прервать, а Thread можно

answersWrong

Thread наследуется только от Thread, а Runnable можно применять к любому классу


questions

Как создать Handler, связанный с фоновым потоком, а не с main thread?

answersCorrect

Вызвать Looper.prepare() в фоновом потоке, создать Handler, затем вызвать Looper.loop().