
SDK
Context
Интерфейс, предоставляющий доступ к информации о текущем состоянии приложения и его среде выполнения. Это основной компонент, который позволяет объектам взаимодействовать с системными ресурсами и службами. Божественный объект.
• Доступ к ресурсам: Через Context можно получить доступ к ресурсам приложения, таким как строки, изображения и макеты, используя методы вроде getResources и getString.
• Запуск компонентов: Context позволяет запускать активити, сервисы и получать доступ к BroadcastReceiver. Например, метод startActivity используется для запуска новых Activity.
• Доступ к файловой системе: Через Context можно получить доступ к файловой системе приложения, используя методы getFilesDir, getCacheDir и другие.
• Преференции: Для работы с хранилищем предпочтений можно использовать методы getSharedPreferences.
• Системные службы: Context позволяет получить доступ к различным системным службам, например, через метод getSystemService, чтобы взаимодействовать с компонентами, такими как LocationManager, ConnectivityManager, и другими.
// Получение Application Context
val appContext = context.applicationContext
// Запуск новой активити
val intent = Intent(context, NewActivity::class.java)
context.startActivity(intent)
// Доступ к ресурсам
val myString = context.getString(R.string.my_string)
// Работа с SharedPreferences
val prefs = context.getSharedPreferences("my_prefs", Context.MODE_PRIVATE)Application Context
Context, привязанный к жизненному циклу приложения. Он существует столько, сколько работает приложение, и используется для действий, не зависящих от Activity или их состояния.
Activity Context
Context, связанный с конкретной Activity. Используется для работы с ресурсами, запуском новых Activity, доступом к системным сервисам, а также взаимодействия с элементами пользовательского интерфейса.
Service Context
Позволяет сервису взаимодействовать с системными ресурсами и компонентами.
Bundle
Используется для передачи данных между компонентами приложения. Работает как контейнер для ключей и значений, поддерживает сериализацию данных для сохранения состояния или межкомпонентного взаимодействия.
• Буфер транзакций Binder имеет фиксированный размер 1 MB, который используется всеми транзакциями в процессе, если размер превышен генерируется TransactionTooLargeException
val bundle = Bundle()
bundle.putString("key", "value")
bundle.putInt("number", 42)Application
Базовый класс в Android, который предоставляет глобальный контекст для всего приложения.
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
}
}<application
android:name=".MyApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" />onCreate
Вызывается один раз при запуске приложения. Используется для глобальной инициализации.
registerActivityLifecycleCallbacks
Позволяет отслеживать жизненный цикл всех Activity в приложении.
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(object: ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
})
}
}
Parcelable
| https://developer.android.com/kotlin/parcelize |
Позволяет эффективно сериализовать объекты для передачи между компонентами приложения, такими как Activity и Service, или для сохранения состояния.
data class User(val name: String, val age: Int): Parcelable {
constructor(parcel: Parcel): this(
parcel.readString() ?: "",
parcel.readInt()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeInt(age)
}
override fun describeContents(): Int = 0
companion object {
@JvmField
val CREATOR: Parcelable.Creator<User> = object: Parcelable.Creator<User> {
override fun createFromParcel(parcel: Parcel): User {
return User(parcel)
}
override fun newArray(size: Int): Array<User?> {
return arrayOfNulls(size)
}
}
}
}Sensor
| https://developer.android.com/reference/android/hardware/Sensor |
Предоставляет методы для определения возможностей, которые доступны конкретному датчику.
SensorManager
| https://developer.android.com/reference/android/hardware/SensorManager |
Предоставляет методы регистрации активности с датчиков и их калибровки.
SensorEvent
| https://developer.android.com/reference/android/hardware/SensorEvent |
Предоставляет необработанные данные датчика, включая информацию о точности.
SensorEventListener
| https://developer.android.com/reference/android/hardware/SensorEventListener |
Интерфейс, который определяет методы обратного вызова, которые будут получать уведомления о событиях датчика.
Window
| https://developer.android.com/reference/android/view/Window |
Это абстрактный класс, который не является наследником Activity Fragment или View. Класс Window контролирует что и как рисуется на экране. Активити имеет один инстанс Window который можно получить методом getWindow. Window в свою очередь, имеет объект Surface и единственную иерархию View. Android-приложение использует WindowManager для создания объектов типа Window и Surface на котором рисуется контент Window. Когда UI должен обновиться, на объекте Surface вызывается метод lockCanvas который возвращает объект типа Canvas. Canvas передается вниз по иерархии View ассоциированной с Window и каждая view рисует себя на канвасе.
Permissions
Runtime Permissions (Dangerous)
Опасные разрешения, предоставляющие доступ к данным с ограниченным доступом и действиям, которые существенно влияют на систему и другие приложения. Начиная с API 23 перед перед выполнением опасных действий нужно запросить у пользователя разрешение в runtime.
• Dangerous sa
mples: location contacts storage contacts phone calls camera microphone.
shouldShowRequestPermissionRationale
Метод, который используется для того, чтобы узнать, нужно ли показывать пользователю объяснение, почему приложению требуется разрешение. Возвращает true, если пользователь ранее отклонял запрос на разрешение, но не выбрал «больше не спрашивать». Этот метод помогает улучшить пользовательский опыт, предлагая объяснение перед повторным запросом разрешения.
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
// Показать объяснение, почему нужно разрешение на камеру
showPermissionExplanationDialog()
} else {
// Запросить разрешение
requestPermissions(arrayOf(Manifest.permission.CAMERA), CAMERA_REQUEST_CODE)
}Notifications
Notification Channel
Начиная с Android 8.0 (API level 26) для каждого уведомления необходимо указывать канал. Пользователь может управлять визуальным и звуковым поведением, которое будет применяться ко всем уведомлениям в канале. Например, разные каналы в приложении часы для будильников, таймеров, секундомеров
LruCache
Кэш, который содержит ссылки на ограниченное количество значений. При каждом доступе к объекту оно перемещается в начало очереди. При добавлении объекта, если кэш переполнен, значение в конце вытесняется и может быть собрано сборщиком мусора. По умолчанию размер кэша измеряется количеством записей. Следует использовать, когда загрузка ресурсов влияет на отзывчивость приложения (хранить эскизы изображений)
val maxMemory: Long = Runtime.getRuntime().maxMemory() / 1024
val cacheSize: Int = (maxMemory / 8).toInt()
val lruCache: BitmapCache = BitmapCache(cacheSize)
class BitmapCache(maxSize: Int): LruCache<String, Bitmap>(maxSize) {
fun getBitmapFromMemory(key: String): Bitmap? {
return this.get(key)
}
fun setBitmapToMemory(key: String, bitmap: Bitmap) {
if (getBitmapFromMemory(key) == null) {
this.put(key, bitmap)
}
}
}Reflection
Механизм исследования данных о программе во время её выполнения. Рефлексия позволяет исследовать информацию о полях, методах и конструкторах классов.
class Bank {
private val money = "$300"
}
fun main() = runBlocking {
val money = Bank::class
.memberProperties
.first { it.name == "money" }
.apply { isAccessible = true }
.get(Bank()) as String
println(money)
}Annotations
@RequiresApi
Указывает, что метод, класс или поле требует определенного уровня API (или выше) для использования. Помогает предотвратить ошибки на устройствах с более старыми версиями Android, где этот API недоступен.
@RequiresApi(21)
fun useLollipopFeature() {
// Метод доступен на Android 5.0 (API 21) и выше
}
fun main() {
if (Build.VERSION.SDK_INT >= 21) {
useLollipopFeature() // Этот метод вызовется только на Android 5.0 (API 21) и выше
}
}@TargetApi
Указывает компилятору и IDE, что код, обернутый в эту аннотацию, ориентирован на указанный уровень API, даже если он выполняется на более ранних уровнях API. Эта аннотация позволяет временно подавить предупреждения о несовместимости API, когда разработчик уверен, что выполняется проверка уровня API перед вызовом кода, зависящего от конкретного API.
@TargetApi(26)
fun useOreoFeature() {
// Этот код предназначен для Android 8.0 (API 26) и выше
val notificationChannel = NotificationChannel("channel_id", "Channel", NotificationManager.IMPORTANCE_DEFAULT)
// ...
}@CheckSdkIntAtLeast
Указывает минимальную версию Android, на которой можно вызывать метод. Статический анализатор проверяет, чтобы код соответствовал этим требованиям.
@CheckSdkIntAtLeast(29)
fun useNewApiFeature() {
// Код, использующий API из Android 10 (API 29)
}@CallSuper
Указывает, что метод, который переопределяется в дочернем классе, должен вызывать реализацию метода суперкласса. Помогает избежать ошибок, когда реализация суперкласса содержит важную логику, которую нельзя пропускать при переопределении.
open class BaseActivity: AppCompatActivity() {
@CallSuper
override fun onDestroy() {
super.onDestroy()
// Логика, которую необходимо выполнять всегда
println("BaseActivity onDestroy called")
}
}
class MainActivity: BaseActivity() {
override fun onDestroy() {
// Если забыть вызвать super.onDestroy(), аннотация @CallSuper предупредит об этом
super.onDestroy()
println("MainActivity onDestroy called")
}
}StorageStatsManager
Позволяет получать информацию об использовании хранилища приложением.
• Появился в Android 15 (API 35).
val storageStatsManager = ContextCompat.getSystemService(this, StorageStatsManager::class.java) as StorageStatsManager
lifecycleScope.launch(Dispatchers.IO) {
// Запрашиваем статистику хранилища для текущего приложения по UID
val storageStats = storageStatsManager.queryStatsForUid(
StorageManager.UUID_DEFAULT, // UUID хранилища по умолчанию
android.os.Process.myUid() // UID текущего приложения
)
// Размер APK-файлов, занимаемых приложением
val apkBytes = storageStats?.getAppBytesByDataType(StorageStats.APP_DATA_TYPE_FILE_TYPE_APK)
// Размер DEX-оптимизированных файлов (артефактов оптимизации)
val doBytes = storageStats?.getAppBytesByDataType(StorageStats.APP_DATA_TYPE_FILE_TYPE_DEXOPT_ARTIFACT)
// Размер нативных библиотек, используемых приложением
val libBytes = storageStats?.getAppBytesByDataType(StorageStats.APP_DATA_TYPE_LIB)
}Вопросы на собесе (43)
Основные компоненты (6)
- Основные компоненты приложения Android?
•
Activity•
Service•
BroadcastReceiver•
ContentProvider
- Почему основные компоненты называются основными?
Потому что приложение существует пока активен хотя бы один из 4 компонентов.
- Чем основные компоненты отличаются от других компонентов Android?
Основные компоненты нужно объявлять в манифесте. Также без одного из запущенных компонентов не будет существовать процесс приложения.
- Какие из основных компонентов можно не указывать в манифесте?
BroadcastReceiver
- Как вызывать основные компоненты?
•
ActivityчерезstartActivity(Intent)илиstartActivityForResult().•
Serviceс помощьюstartService(Intent)илиbindService().•
BroadcastReceiverчерезsendBroadcast(Intent)или зарегистрировать динамически/статически.•
ContentProviderчерезContentResolverдля выполнения CRUD-операций.
- Что из перечисленного является основными компонентами Android?
•
Application•
Service•
Fragment•
Activity
- Основные компоненты приложения Android?
Context (4)
- Что такое Context?
Это интерфейс, предоставляющий доступ к информации о приложении, таким как ресурсы, базовые функции и служебные классы. Он используется для взаимодействия с системными сервисами и управления жизненным циклом компонентов приложения.
- Разница между Application Context и Activity Context?
Application Contextживет в течение всего времени работы приложения и используется для объектов, которые должны существовать столько же, сколько и само приложение.Activity Contextпривязан к конкретнойActivityи используется для операций, связанных с UI, таких как отображение диалогов или запускActivity.
- Какие есть виды Context?
•
Application Contextдоступен на уровне всего приложения.•
Activity Contextсвязан с конкретной Activity.•
Service Contextиспользуется в cервисах.•
BroadcastReceiver Contextпередается в методах onReceive.
- Какое ключевое слово используется для доступа к ресурсам приложения (например, строкам или изображениям) в коде? (
•
R• resources
•
this•
getResources()
- Что такое Context?
Bundle (6)
- Какие типы данных поддерживает Bundle?
•
BooleanByteCharCharSequenceDoubleFloatIntLongShortString•
String[]CharSequence[]•
Parcelable(включая массивыParcelable[])•
Serializable•
Bundle(вложенныеBundle)•
ArrayList<T>(где T может быть из вышеперечисленных типов илиParcelable/Serializableобъектов)
- Какое ограничение размера у Bundle?
Не имеет строгого ограничения по размеру, но рекомендуется, чтобы размер данных не превышал 1MB. Превышение этого размера может привести к ошибкам и проблемам с производительностью.
- Почему в Bundle введено ограничение на 1 MB?
Ограничение введено для оптимизации производительности и предотвращения проблем с передачей данных между процессами (Binder), так как слишком большие данные могут привести к ошибкам и блокировке IPC (межпроцессного взаимодействия).
- Почему передавать данные между компонентами рекомендуется через Bundle?
Передача данных через
Bundleрекомендуется, потому что это упрощает сериализацию объектов и обеспечивает совместимость с жизненным циклом компонентов Android, обеспечивая сохранение состояния при повороте экрана или других изменениях конфигурации.
- Как сохранить в Bundle сложные объекты? (картинки)
• Сохрани изображение в файловую систему (например, во временной директории) и храните путь к файлу в
Bundleс помощьюputString().• Base64: преобразуй изображение в строку Base64 и сохраните её в
Bundleс помощьюputString(). (Увеличит размер данных).
- В крэшлитике увидели TransacionTooLargeException. Что будем делать?
TransactionTooLargeExceptionвозникает при превышении лимитов данных вIntent. Решение: уменьшить объем данных, использоватьViewModel,SharedPreferencesили базу данных для хранения.
- Какие типы данных поддерживает Bundle?
Parcelable (5)
- Почему в Android рекомендуется использовать Parcelable?
Быстрее будет работать в транзакциях между компонентами.
- В каких случаях не рекомендуется использовать Parcelable?
Когда не хотим зависеть от Android-специфичных классов.
- Разница между Serializable и Parcelable?
•
Serializable— это стандартный интерфейс Java, который медленнее, но проще в использовании, так как требует лишь реализации интерфейсаSerializable.•
Parcelable— это Android-специфический интерфейс, который более эффективен и быстрый, но требует явного определения способов сериализации и десериализации данных.
- Что быстрее Serializable или Parcelable по умолчанию?
Parcelableбыстрее, так как оптимизирован для Android и избегает рефлексии, в отличие отSerializable, который использует более медленный механизм сериализации Java.
- Что быстрее Serializable или Parcelable по режиме ручной настройки?
При ручной настройке
Serializableможет быть быстрее, если оптимизирована логика сериализации, ноParcelableобычно остается предпочтительным для Android из-за лучшей интеграции и производительности в стандартных случаях.
- Почему в Android рекомендуется использовать Parcelable?
Permissions (9)
- Для чего нужны разрешения в Android?
Для контроля доступа приложений к данным и функциям устройства, таким как камера, геолокация или контакты, обеспечивая безопасность и конфиденциальность пользователя.
- Какие виды разрешений бывают в Android?
• Обычные разрешения (Normal permissions) — не представляют серьезной угрозы для конфиденциальности или безопасности пользователя. Пример: доступ к интернету.
• Опасные разрешения (Dangerous permissions) — могут потенциально повлиять на конфиденциальность пользователя и требуют явного согласия. Примеры: доступ к камере, геолокации или контактам.
- В чем разница между dangerous и normal разрешениями?
Dangerous разрешения требуют согласия пользователя, так как могут затрагивать конфиденциальные данные, в то время как normal разрешения не требуют согласия и считаются менее рискованными.
- Какие есть способы запросить разрешение в Android?
•
ActivityCompat.requestPermissions.•
ContextCompat.checkSelfPermission.•
launchPermissionRequestв Compose.
- Можно ли отозвать полученное разрешение?
Да, пользователь может отозвать полученные разрешения в настройках приложения в любой момент.
- Что значит статус show rationale у разрешения?
Статус «show rationale» означает, что приложение может объяснить пользователю, почему ему необходимо разрешение, прежде чем запрашивать его. Это полезно, если пользователь ранее отказал в доступе.
- Как работать с локацией в Android?
Для работы с локацией в Android используют API Google Play Services —
FusedLocationProviderClient, который предоставляет упрощенные методы для получения местоположения устройства. Важно убедиться, что разрешения на местоположение предоставлены, и корректно обрабатывать отказ в доступе. Для получения локации в фоне можно использовать ForegroundServiceс типомlocation. Это обеспечивает непрерывное отслеживание локации, даже когда приложение не активно.
- Как организовать получение текущей геолокации каждые 10-15 секунд?
Использовать
FusedLocationProviderClientс периодическим запросом черезrequestLocationUpdatesи интервалом 10-15 секунд.
- Какой из следующих классов используется для работы с разрешениями в Android?
•
PermissionsHandler•
PermissionsManager•
ActivityCompat•
PermissionsCompat
- Для чего нужны разрешения в Android?
Sensor (1)
- Как получить доступ к данным сенсора в Android-приложении?
Использовать
SensorManager.
- Как получить доступ к данным сенсора в Android-приложении?
Drawable (1)
- Какие типы Drawable существуют в Android?
DrawableBitmapDrawableShapeDrawableLayerDrawableStateListDrawableNinePatchDrawableVectorDrawableAnimationDrawable
- Какие типы Drawable существуют в Android?
Notifications (2)
- Как группировать уведомления в Android?
Группировка уведомлений осуществляется с помощью
NotificationCompat.Builderи методаsetGroup(), который объединяет уведомления под одной группой. МетодsetGroupSummary()позволяет создать сводное уведомление для отображения общего количества уведомлений в группе.
- Для чего нужны каналы в уведомлениях?
• Группировать уведомления: Уведомления с одинаковым каналом можно объединять, что упрощает восприятие.
• Настраивать звуки и приоритеты: Каждый канал может иметь свои настройки, такие как звук, вибрация и важность.
• Управлять подпиской: Пользователь может включать или отключать уведомления для конкретных каналов, что повышает контроль над получаемой информацией.
- Как группировать уведомления в Android?
Annotations (1)
- Разница между
@RequiresApiи@TargetApi?@RequiresApiпроверяет минимальный API для метода/класса на уровне компиляции,@TargetApiподавляет предупреждения о несовместимости API в указанном блоке.
- Разница между
Другие (8)
- Как научить общаться между собой 2 Android-приложения?
•
Intent. Приложение A может отправить запрос приложению B с помощью неявногоIntent. Если приложение B настроено для обработки определенныхIntent, оно сможет принимать эти запросы.• Content Providers. Одно приложение может предоставить доступ к данным через
ContentProvider, а другое приложение — обращаться к этим данным через URI. Это безопасный способ предоставления данных.• Broadcasts: Приложение A может отправлять широковещательные сообщения (Broadcast), которые приложение B будет принимать и обрабатывать с помощью
BroadcastReceiver.• Bound Services: Одно приложение может подключаться к сервису другого приложения, используя интерфейсы AIDL (Android Interface Definition Language), что позволяет взаимодействовать между приложениями через IPC (межпроцессное взаимодействие).
- Что бы ты улучшил в OS Android?
• FindMyDevice
• AirDrop
• Общий буфер обмена
• Нативная реализация без JVM
- Как перехватить все Runtime-исключения в Android-приложении?
Установить
Thread.setDefaultUncaughtExceptionHandlerвApplication.onCreate
- Может ли приложение работать в рамках нескольких процессов?
Да, используя атрибут
android:processв манифесте для компонентов. Это позволяет изолировать ресурсы и повышать производительность, но требует межпроцессного взаимодействия.
- Какие преимущества дает работа в нескольких процессах?
Работа в нескольких процессах обеспечивает изоляцию данных, повышая безопасность и стабильность. Это позволяет выполнять долгие задачи без блокировки основного потока, улучшает использование ресурсов и повышает устойчивость к сбоям, так как ошибки в одном процессе не влияют на другие.
- Какие есть способы сохранения состояния в Android?
•
onSaveInstanceStateсохраняет временное состояние активити при её уничтожении.•
ViewModelсохраняет данные при изменении конфигурации, например, при повороте экрана.•
SharedPreferencesхранит простые данные (ключ-значение) между сессиями.•
DataStoreсовременный способ хранения настроек и данных в виде ключ-значение.•
Roomиспользует SQLite для хранения структурированных данных.• Files: сохраняет данные в виде файлов во внутреннем или внешнем хранилище.
- Способы безопасного хранения данных в Android?
•
EncryptedSharedPreferencesдля безопасного хранения паролей и конфиденциальной информации.•
SQLiteс шифрованием: ИспользуйтеSQLCipherдля шифрования баз данныхSQLite.• Файлы с шифрованием: Шифруйте файлы перед их сохранением в хранилище устройства, используя алгоритмы шифрования, такие как AES.
•
Keystoreхраните криптографические ключи в Android Keystore для безопасного доступа и использования.•
ContentProviderдля контроля доступа к данным и обеспечения их безопасности через разрешения.
- Какие есть виды диплинков?
• Стандартные диплинки: используют URL-схемы для открытия определённых активити в приложении (например, myapp://path/to/resource).
• Виртуальные диплинки (App Links): используют HTTP-URL и позволяют открывать приложение, а также обрабатывать ссылки в браузере, если приложение не установлено.
- Какой первый класс вызовется при запуске Android-приложения?
Application
- Как научить общаться между собой 2 Android-приложения?