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?
•
Boolean
Byte
Char
CharSequence
Double
Float
Int
Long
Short
String
•
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?
Drawable
BitmapDrawable
ShapeDrawable
LayerDrawable
StateListDrawable
NinePatchDrawable
VectorDrawable
AnimationDrawable
- Какие типы 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-приложения?