Архітектура Android Application
Last updated
Last updated
Програми для Android можна писати мовами Kotlin, Java та C++. Інструменти Android SDK компілюють ваш код разом з будь-якими файлами даних та ресурсів в APK або Android App Bundle .
Android package , який є архівним файлом з розширенням .apk , містить вміст програми Android, яка потрібна під час виконання, і це файл, який пристрої під керуванням Android використовують для встановлення програми.
Пакет , який є архівним файлом з розширенням .aab , містить вміст проекту Android, включаючи деякі додаткові метадані, які не потрібні під час виконання. AAB - це формат для публікації в маркеті, який не можна встановити на пристроях Android, він відкладає створення APK та підписання на пізніший етап. Наприклад, при розповсюдженні вашої програми через Google Play сервери Google Play генерують оптимізовані APK-файли, які містять лише ресурси та код, які потрібні конкретному пристрою, що запитує інсталяцію програми.
Кожна програма Android знаходиться у власному ізольованому програмному середовищі безпеки або пісочниці (security sandbox ), захищеному наступними функціями безпеки Android:
Операційна система Android - це розрахована на багато користувачів система Linux, в якій кожен додаток є окремим користувачем. За замовчуванням система призначає кожному додатку унікальний ідентифікатор користувача Linux (ідентифікатор використовується лише системою та невідомий додатку);
Система встановлює дозволи для всіх файлів у програмі, так що лише ідентифікатор користувача, призначений цій програмі, може отримати доступ до них;
Кожен процес має власну віртуальну машину (VM), тому код програми працює ізольовано від інших додатків;
За замовчуванням кожна програма працює у своєму процесі Linux. Система Android запускає процес, коли необхідно виконати будь-який з компонентів програми, а потім завершує процес, коли він більше не потрібен або коли необхідно відновити пам'ять для інших програм.
У системі Android реалізовано принцип найменших привілеїв. Тобто кожен додаток за замовчуванням має доступ тільки до тих компонентів, які необхідні йому для роботи, і не більше. Це створює дуже безпечне середовище, в якому програма не може отримати доступ до частин системи, для яких у нього немає дозволу. Однак є способи для програми обмінюватися даними з іншими програмами та для програми для доступу до системних служб:
Можна організувати дві програми для використання того самого ідентифікатора користувача Linux, і в цьому випадку вони зможуть отримати доступ до файлів один одного. Для економії системних ресурсів програми з тим самим ідентифікатором користувача також можуть працювати в одному процесі Linux і спільно використовувати одну і ту ж віртуальну машину;
Програми також мають бути підписані тим самим сертифікатом. Програма може вимагати дозволу на доступ до даних пристрою, таких як розташування пристрою, камера та з'єднання Bluetooth. Користувач повинен явно надати ці дозволи. Для отримання додаткових відомостей див. розділ « ».
Компоненти програми
Компоненти програми є основними будівельними блоками Android програми. Кожен компонент - це точка входу, через яку система або користувач можуть увійти до вашої програми. Деякі компоненти залежать від інших. Є чотири різних типи компонентів програми:
Activities;
Services;
Broadcast receivers;
Content providers.
Кожен тип служить певної мети та має окремий життєвий цикл, який визначає, як компонент створюється та знищується.
Почнемо розбиратися з таких компонентів, як активити та фрагменти, та розглянемо кейси, коли система може припинити їхню роботу.
Активіти та фрагменти (activities and fragments)
З точки зору тестувальника активити можна сприймати як екран, на якому відображаються елементи. Програма складається, як мінімум, з однієї активіті. По суті, активіті – це контейнер для UI-компонентів. Якщо активити – це контейнер, то фрагменти – це UI-компоненти активіті. Фрагмент також є контейнером для UI-компонентів. Є класна аналогія з браузером (дякую розробникам!) для наочнішого уявлення про те, як між собою пов'язані активіті та фрагменти. Припустимо, що у нас відкрито кілька вікон одного браузера. Це дещо активіті всередині однієї програми.
Всередині вікна можна відкрити кілька вкладок. Це фрагменти усередині активіті.
Фрагменти працюють трохи швидше, ніж активіті. Але на сучасних пристроях різниця практично невідчутна. Залежно від того, яким чином вирішується завдання, розробник може написати програму лише на активіті або активіті з використанням фрагментів.
Операційна система при управлінні життєвим циклом програми працює саме з активіті програми. Тому поки що нас найбільше цікавить життєвий цикл активіті.
Користувачі запускають велику кількість програм, а отже, створюється багато процесів з активіті. Кожен запущений процес з'їдає оперативну пам'ять пристрою, і її дедалі менше. Але Андроїд ретельно стежить за процесами і у разі нестачі ресурсів для виконання пріоритетнішої роботи закриває ті, які менш пріоритетні. Давайте розберемося, коли програма «вразлива» до таких рішень системи і як це може вплинути на його працездатність.
Життєвий цикл активіті
Після запуску та до завершення активіті завжди перебуває в одному із статусів. У тестуванні це корисно для розуміння потенційно проблемних кейсів і в контексті тестування переривань (Interrupt testing):
Перед завершенням Activity будуть викликані відповідні методи життєвого циклу;
Метод onPause() повинен зупинити всі "слухання" та оновлення інтерфейсу. Метод onStop() повинен зберігати дані програми. І, нарешті, метод onDestroy() звільнить будь-які ресурси, виділені для Activity;
Коли користувач перемикається назад на програму, яка була перервана системною подією, викликається метод onResume(). На основі збережених даних, можуть перереєструватися «слухачі» та переключитись оновлення інтерфейсу.
Життєвий цикл активіти представлений такими станами:
Тепер наведу приклади. Вони покривають основні кейси, з якими ми найчастіше стикаємося під час тестування.
Перший запуск програми
При першому запуску програми створюється та завантажується головна активіті у програмі.
При переході в стан "Resumed" активіті доступна для взаємодії з користувачем. Все чудово, проблем немає.
Перехід із першого екрана на другий
Крок 1: При переході з першого екрана на другий активіті першого екрана спочатку встає на паузу. У цей момент можуть виконуватися такі дії, як збереження введених даних та зупинення ресурсомістких операцій (наприклад, програвання анімацій). Це відбувається досить швидко та невідчутно для користувача.
Крок 2, 3, 4: Запуск активувати другий екран.
Крок 5: Зупиняється активувати перший екран. Також у випадку, якщо Андроїд в цей момент намагається звільнити пам'ять, активіті першого екрану додатково може перейти в стан Destroyed (тобто знищитися).
Щоб краще зрозуміти, що являє собою стан «Paused» давайте уявимо таку ситуацію: екран, поверх якого з'явився алерт. Ми не можемо з ним взаємодіяти, але водночас ми його бачимо.
Повернення з другого екрана на перший
При поверненні з другого екрана на перший відбувається майже те саме, тільки перша активіті не створюється заново. Вона підвантажується з пам'яті (якщо, звісно, була знищена системою). Друга активіті знищується після того, як була зупинена, оскільки вона забирається зі стеку переходів.
Згортання та вихід із програми
При згортанні програми (наприклад, за кнопкою Home) активіті зупиняється.
Важливо, щоб під час розгортання програми активіті коректно відновилася та дані збереглися.
На всіх екранах намагаємося перевіряти згортання-розгортання програми. Цей кейс є особливо актуальним на формах введення. Погодьтеся, буде прикро, якщо текст листа, який ви так старанно набирали, зітреться при банальному згортанні програми. Або форма, що складається з багатьох полів, знову стане порожньою.
При виході з програми (по апаратній кнопці назад) крім кроку 1 і кроку 2 виконується крок 3. Активіті знищується і при наступному запуску програми створюється заново.
Поворот екрану
Один із значних випадків, який плодить баги – це поворот екрану. Виявляється, при повороті екрана активіті проходить повний цикл життя. А саме знищується та знову створюється. І так за кожного повороту. Тому, знову ж таки, перевіряємо поворот на кожному екрані.
Підтримка горизонтальної орієнтації екрану, з одного боку, дозволяє перевірити коректність роботи всіх етапів активіті, з іншого боку значно збільшує кількість тест-кейсів.
Багатовіконний режим
Починаючи з Андроїда 7 (з Андроїда 6 як експериментальна фіча) став доступний багатовіконний режим. Користувачі отримали можливість бачити відразу кілька програм на екрані одночасно. При цьому тільки та програма, з якою користувач зараз взаємодіє, знаходиться в стані «Resumed». Інші встановлюються у стан «Paused».
Don't keep activities (Не зберігати дії)
Чи потрібно перевіряти повний життєвий цикл активіті, якщо програма не підтримує поворот екрана? Звісно, треба.
Якщо оперативна пам'ять давно не чистилася, її не дуже багато, і в паралелі з вашим додатком було запущено якийсь ресурсомісткий додаток (наприклад, Pokemon Go), то шанс, що Android вирішить «прибити» процес з вашої активіті при переключенні на інший додаток зростає.
Як перевірити правильність роботи програми вручну, якщо вона не підтримує поворот екрана? Досить просто: встановити галку «don't keep activities» в налаштуваннях розробника та перезапустити програму.
У цьому випадку емулює ситуація, коли пам'яті не вистачає і Андроїд знищує всі активіті, з якими користувач зараз не взаємодіє, залишаючи тільки ту, що зараз активна.
Це не означає, що галка повинна завжди бути включеною при тестуванні, але періодично дивитися додаток з опцією "не користуватися активністю" корисно, щоб користувачі зі слабкими пристроями не сильно страждали і не лаяли нас.
Broadcast receiver (широкомовний приймач)
Для обробки зовнішніх подій використовується Broadcast receiver. Програма може підписуватися на події системи та інших програм. Андроїд доставляє подію додатку-передплатнику, навіть якщо він не запущено, і таким чином може «мотивувати» його запуск.
При тестуванні нам важливо розуміти, які очікуються на події і як вони обробляються.
Наприклад, у коді заздалегідь було прописано, що програма чекає на повідомлення від конкретного номера і має доступ до смс. Коли користувачу прийде секретний код, Broadcast receiver отримає повідомлення і в полі підтвердження операції буде введено смс-код.
Сервіси (Services)
Ще одна дуже важлива річ в Андроїді – це сервіси. Вони необхідні виконання фонових завдань. При цьому програма не обов'язково має бути відкрито користувачем у цей момент.
Сервіси мають кілька режимів роботи. Користувач може бачити, що сервіс запущено, а може і зовсім не помічати його.
Якщо ви почули чарівне слово "сервіс" від розробника, не полінуйтеся, з'ясуйте, яку логіку роботи заклали в нього:
Що робить сервіс і в якому вигляді поводиться?
Як поводиться сервіс, коли програма не активна?
Чи відновлюється сервіс після переривання (дзвінка, що входить, перезапуску телефону)?
Тут основна порада при проектуванні тестових сценаріїв - це обміркувати кейси, коли робота сервісу може перерватися або почати конфліктувати з роботою іншого сервісу. Найпідступніші ситуації: коли робота сервісу починається, а користувач цього не чекав. І тут корисно дізнатися, що може спровокувати запуск сервісу.
Найпростіші і нешкідливі – це сервіси без додаткових параметрів . При ручному тестуванні ми найчастіше не помічаємо їхню роботу. Наприклад, якщо потрібно відправити дані в систему аналітики, то для цього завдання нерідко використовують такі сервіси.
Ще один тип сервісів – це sticky-сервіси . Якщо робота такого сервісу раптово завершиться, то згодом sticky-сервіс «відродиться». Примітно, що з кожним разом період до відродження збільшується, щоб він менше заважав роботі системи. У деяких додатках прикладом sticky-сервісу може бути завантаження файлів на пристрій. Можливо, ви помічали, якщо в «шторці» скинути завантаження, то через якийсь час вона може відновитися і продовжити завантажувати файли.
Найважливіші сервіси - ті, роботу яких користувач відчуває на собі і вона для нього важлива. Вони називаються foreground-сервіси , і у них обов'язково є нотифікація в "шторці", яку користувач не може закрити. Система їх знищуватиме в останню чергу, оскільки пріоритет у таких сервісів найвищий.
Наприклад, музичний програвач. Якщо згорнути програму і навіть закрити її, то плеєр продовжує грати, поки користувач не поставить його на паузу або не закриє. Або поки що інший додаток або система не призупинить його роботу. Зокрема, для музичного програвача варіантів може бути багато: вхідний дзвінок, інший музичний додаток, звукова нотифікація.
Якщо мова зайшла про музичні плеєри, то варто відзначити таке поняття, як аудіофокус.
Аудіофокус
Припустимо, що при запуску кількох аудіоплеєрів, вони всі гратимуть одночасно. Навряд це комусь сподобається. Тут на допомогу приходить аудіофокус, який запитується додатком системи. У разі звичайного запиту аудіофокуса система ніби сповіщає всі запущені програми: «Зараз інший додаток буде говорити, помовчіть, будь ласка». Смішно, але це відбувається саме у форматі прохання.
Якщо ваш додаток не дуже ввічливий, він спокійно може проігнорувати запит. Наше завдання – перевіряти ці ситуації.
Компромісний режим запиту аудіофокуса називається " тимчасовим перехопленням аудіофокуса ". Це означає, що вашому додатку повернеться аудіофокус, коли його передає сигнал, що аудіофокус звільнений.
Ще один вид запиту аудіофокуса – це « duck ». Він просить інші програми не мовчати, а зменшити гучність наполовину поки відтворюється звук запитуючого фокус програми. Наприклад, такий запит використовується під час відтворення звуку нотифікації про нове повідомлення в месенджері.
Тестування аудіофокуса дуже важливе, т.к. тут все пов'язано на совісті розробників і система не бере особливої участі у вирішенні конфліктів. Ну а якщо баг таки вилізе до користувачів, то не сумнівайтеся, вони швидко вам про це повідомлять.
На цьому, мабуть, поки що можна закінчити. Звичайно, є ще багато деталей і немає необхідності враховувати абсолютно все під час тестування. На мій досвід, тестувальнику необхідно розуміти з чого складається додаток і як він працює. Це дає можливість аналізувати непрості баги, які виникають на перетині бізнес-логіки програми та особливостей роботи операційної системи. Особливо якщо справа стосується Андроїда.
Content providers
Постачальник контенту керує загальним набором даних програми, які ви можете зберігати у файловій системі, у базі даних SQLite, в Інтернеті або в будь-якому іншому постійному сховищі, до якого ваш додаток може отримати доступ. Через постачальника вмісту інші програми можуть запитувати або змінювати дані, якщо постачальник вмісту дозволяє це. Наприклад, Android надає постачальника контенту, який керує контактною інформацією користувача. Таким чином, будь-яка програма з відповідними дозволами може запитувати постачальника вмісту, наприклад ContactsContract.Data, для читання та запису інформації про конкретну людину. Заманливо думати про провайдера контенту як про абстракцію бази даних, тому що для цього поширеного випадку в них вбудовано безліч API та вбудовану підтримку. Проте з погляду системного дизайну вони мають інше основне призначення. Для системи постачальник контенту - це точка входу в додаток для опублікування іменованих елементів даних, ідентифікованих схемою URI. Таким чином, програма може вирішити, як вона хоче зіставити дані, які вона містить, з простором імен URI, передаючи ці URI іншим об'єктам, які, у свою чергу, можуть використовувати їх для доступу до даних.
Унікальний аспект системи Android полягає в тому, що будь-яка програма може запускати компонент іншої програми. Наприклад, якщо ви хочете, щоб користувач зробив знімок за допомогою камери пристрою, ймовірно, є інша програма, яка робить це, і ваша програма може використовувати його замість розробки дії для самостійної зйомки фотографії. Вам не потрібно включати або навіть посилатися на код із програми камери. Натомість ви можете просто запустити дію у додатку камери, яка робить знімок. Після завершення фотографія навіть повертається у вашу програму, щоб ви могли її використовувати. Користувачеві здається, що камера насправді є частиною вашої програми.
Коли система запускає компонент, вона запускає процес для цієї програми, якщо вона ще не запущена, і створює екземпляри класів, необхідних компоненту. Наприклад, якщо ваша програма запускає дію в програмі камери, яка робить знімок, ця дія виконується в процесі, що належить додатку камери, а не в процесі вашої програми. Отже, на відміну від програм у більшості інших систем, програми Android не мають єдиної точки входу (немає функції main ()). Оскільки система запускає кожну програму в окремому процесі з правами доступу до файлів, які обмежують доступ до інших програм, ваша програма не може безпосередньо активувати компонент з іншої програми. Однак система Android може. Щоб активувати компонент в іншій програмі, доставте системі повідомлення,intent ) запустити конкретний компонент. Потім система активує компонент для вас.
Активація компонентів (Activating components)
Три з чотирьох типів компонентів - activity, services, and broadcast receivers - активуються асинхронним повідомленням, званим intent . Наміри пов'язують окремі компоненти один з одним під час виконання. Ви можете думати про них як про месенджерів, які запитують дію в інших компонентів, незалежно від того, чи належить компонент вашому додатку чи іншому. Намір створюється за допомогою об'єкта Intent, який визначає повідомлення для активації певного компонента (explicit intent), або певного типу компонента (implicit intent).
Файл маніфесту (The manifest file)
Перш ніж система Android зможе запустити компонент програми, система повинна знати, що компонент існує, прочитавши файл маніфесту AndroidManifest.xml. Ваша програма повинна оголосити всі свої компоненти в цьому файлі, який повинен знаходитися в корені каталогу проекту програми. Маніфест виконує ряд функцій на додаток до оголошення компонентів програми, наприклад:
Визначає будь-які дозволи (user permissions), які потрібні програмі, такі як доступ в Інтернет або доступ для читання контактів користувача;
Оголошує мінімальний рівень API, необхідний програми, залежно від того, які API використовує додаток;
Оголошує апаратні та програмні функції, що використовуються або необхідні програмою, такі як камера, служби Bluetooth або сенсорний екран;
Оголошує бібліотеки API, з якими потрібно зв'язати програму (крім API-інтерфейсів Android framework), наприклад бібліотеку Google Maps.
Ресурси програми (App resources)
Додаток Android складається з більшого, ніж просто коду - для нього потрібні ресурси, окремі від вихідного коду, такі як зображення, аудіофайли та все, що пов'язане з візуальним поданням програми. Наприклад, ви можете визначати анімацію, меню, стилі, кольори та макет інтерфейсів дій користувача за допомогою файлів XML. Використання ресурсів програми дозволяє легко оновлювати різні характеристики вашої програми без зміни коду. Надання наборів альтернативних ресурсів дозволяє оптимізувати програму для різних конфігурацій пристроїв, наприклад, для різних мов та розмірів екрана.
Для кожного ресурсу, який ви включаєте в свій проект Android, інструменти збирання SDK визначають унікальний цілий ідентифікатор, який ви можете використовувати для посилання на ресурс з коду вашої програми або з інших ресурсів, визначених у XML. Наприклад, якщо ваша програма містить файл зображення з ім'ям logo.png (збережений у каталозі res/drawable/), інструменти SDK генерують ідентифікатор ресурсу з ім'ям R.drawable.logo. Цей ідентифікатор порівнюється з цілим числом для конкретної програми, яку ви можете використовувати для посилання на зображення та вставки його у свій інтерфейс користувача.
Одним з найважливіших аспектів надання ресурсів окремо від вихідного коду є можливість надання альтернативних ресурсів для різних конфігурацій пристроїв. Наприклад, визначаючи рядки інтерфейсу користувача в XML, ви можете перевести рядки на інші мови і зберегти ці рядки в окремих файлах. Потім Android застосовує відповідні мовні рядки до вашого інтерфейсу користувача на основі кваліфікатора мови, який ви додаєте до імені каталогу ресурсів (наприклад, res / values-fr / для французьких рядкових значень) і мовних налаштувань користувача.
Android підтримує безліч різних кваліфікаторів для альтернативних ресурсів. Кваліфікатор - це короткий рядок, який ви включаєте в ім'я своїх каталогів ресурсів, щоб визначити конфігурацію пристрою, для якого слід використовувати ці ресурси. Наприклад, ви повинні створити різні макети для своїх занять залежно від орієнтації та розміру екрана пристрою. Коли екран пристрою знаходиться в портретній орієнтації (високий), ви можете захотіти, щоб макет з кнопками був вертикальним, але коли екран знаходиться в альбомній орієнтації (широкий), можна вирівняти кнопки по горизонталі. Щоб змінити макет залежно від орієнтації, ви можете визначити два різних макетів та застосувати відповідний кваліфікатор до імені каталогу кожного макету.
Джерела:
Дод. матеріал:
Щоб отримати додаткові відомості про різні типи ресурсів, які ви можете включити до своєї програми, і про те, як створювати альтернативні ресурси для різних конфігурацій пристроїв, див. розділ « ». Щоб дізнатися більше про передові методи розробки та розробки надійних програм виробничої якості, див. .
YaTalks 2021. Mobile: +