Програми для Android пишуться на мові програмування Java. Інструментарій Android SDK компілює ваш код разом з іншими даними і файлами ресурсів у файл APK — Пакет Android (Android Packege), який представляє собою архів з розширенням apk. Даний файл містить усі компоненти програми для Android і використовується для встановлення Android-машинами.
Рекомендуємо також для прочитання статтю "Перша програма “Привіт, Світ!” на Android".
На кожному пристрої з встановленим Android, усі програми виконуються у своїх власних “пісочницях”:
- Операційна система Android є багато-користувацькою системою у якій кожна програма являє собою окремого користувача.
- За замовчуванням, система присвоює кожному користувачу унікальний ідентифікатор користувача (ідентифікатор використовується системою і не відомий для програми). Система встановлює правила доступу для усіх файлів програми, отож тільки присвоєний їй ідентифікатор користувача може отримати до них доступ.
- Кожен процес має свою віртуальну машину (VM — Virtual Machine), отож код програми виконується в ізоляції по відношенню до інших.
- За умовчанням, кожна програма виконується у одному Linux-процесі. ОС Android запускає процес коли будь-який з компонентів програми потребує виконання, після цього завершує процес, коли його виконання не потрібне, або коли система повинна виділити пам'ять для інших процесів.
Таким чином, ОС Android реалізовує принцип найменших привілей. Тобто, кожна програма, за умовчанням, має доступ тільки до тих компонентів, які вимагаються для виконання її роботи. Це створює безпечне середовище у якому програма не може отримати доступ до компонентів системи, до яких їй не дозволено звертатись.
Однак, існують методи обміну інформації між програмами і доступу до системних сервісів:
- Існує спосіб організувати використання одного ідентифікатора користувача для двох програм, що дає їм змогу спільно використовувати файли. Для збереження системних ресурсів, програми з спільним ідентифікатором користувача, можна організувати у один Linux-процес з одною віртуальною машиною.
- Програми можуть запитати про доступ до даних пристрою, на подобі контактів користувача, SMS-повідомлень, зовнішніх пристроїв накопичення (SD-карти), вбудованих камер, Bluetooth і інших. Користувач повинен безпосередньо надати необхідні дозволи.
Компоненти програми
Компоненти програм являються складовими будівними блоками Android-застосунку. Кожен компонент являється точкою, через яку система може ввійти у вашу програму. Не усі компоненти являються безпосередніми точками входу у програму для користувача і деякі залежать один-від-одного, але кожен існує як окрема сутність і грає певну роль — кожен являється унікальним будівним блоком, який допомагає визначити поведінку вашої програми.
Існує чотири різних типи компонентів. Кожен тип служить певній цілі і має визначений життєвий цикл, який визначає як компонент створюється і руйнується. Вони наступні:
Дії (Activities)
Дії представляють один екран з інтерфейсом користувача. Наприклад, програма електронної пошти містить одну дію, яка показує список нових електронних листів, інша дія для створення листа, і дія для читання листів. Хоча дії працюють разом для формування хорошого досвіду користувача у користуванні програмою, кожен з них є незалежним від інших. В такому разі, інша програма може запустити будь-який з даних дій (якщо програма електронних повідомлень дозволить це). Наприклад, програма вбудованої камери може запустити дію у програмі електронних повідомлень, яка створює нові повідомлення, щоб користувач поділився зображенням з іншими. Дія реалізовується як потомок класу Activity.
Сервіси (Services)
Сервіс являється компонентом, який виконується на задньому плані для виконання довготривалих операцій, або для виконання роботи у віддалених процесах. Сервіс немає інтерфейсу користувача. Наприклад, сервіс може грати музику на задньому плані, поки користувач працює з іншою програмою, або може отримувати дані з мережі без блокування взаємодії користувача з дією (Acivity). Інший компонент, на подобі дії, може запустити сервіс і дозволити зв'язуватись з ним для забезпечення взаємодії між програмами. Сервіс реалізовується в якості потомка класу Servise.
Постачальники контенту (Content Providers)
Постачальник контенту управляє загальнодоступними даними програми. Ви можете зберігати дані у файловій системі, у базі даних SQLite, в Інтернеті або в будь-якому іншому місці постійного зберігання даними, до яких може звернутися програма. Через постачальника контенту інші програма можуть отримувати, чи, навіть, змінювати дані (якщо постачальник контенту дозволив це). Наприклад, система Android забезпечує постачальник контенту, який управляє інформацією про контакти користувача. В такому разі, програма у якої є відповідні дозволи може отримати частину постачальника контенту (на подобі ContactsContract.Data) для зчитування і запису інформації про певну персону.
Постачальники контенту корисні також для зчитування і запису даних, які являються приватними для вашої програми і не розподіляються. Наприклад, програма Note Pad використовує постачальник контенту для збереження нотаток.
Постачальник контенту реалізовується у вигляді потомка класу ContentProvider і повинен реалізувати стандартний набір методів, які дозволять іншим користувачам виконувати транзакції.
Отримувач загальносистемних повідомлень
Обробник або отримувач загальносистемних повідомлень являється компонентом, який відповідає на загальносистемні повідомлення. Велика кількість повідомлень генерується системою, наприклад, повідомлення яке вказує на те, що екран вимкнено, батарея має малий заряд, або було зроблено фотографію. Програми можуть також генерувати загальносистемні повідомлення, наприклад, для того щоб інші програмами “дізнались”, що деякі дані були завантаженими на пристрій і стали доступними для використання. Хоча отримувачі повідомлень не мають інтерфейсу, вони можуть створювати оповіщення для ознайомлення користувача з загальносистемною подією. В загальному, отримувачі загальносистемних повідомлень являють собою “шлюз” до інших компонентів і призначенні для виконання мінімальної кількості роботи. Наприклад, вони можуть ініціювати роботу сервісу базуючись на певній події. Отримувачі загальносистемних повідомлень являються потомками класу BroadcastReceiver і кожне повідомлення надсилається, як об'єкт класу Intent.
Унікальним аспектом дизайну ОС Android являється те, що кожна програма може запустити компонент іншої системи. Наприклад, якщо ви бажаєте, щоб користувач зробив фото за допомогою камери пристрою, ймовірно, в системі присутня програма як виконує це і ваша програма може її використати. Вам не потрібно зв'язуватись з кодом програми, яка відповідає за камеру. Замість цього, ви можете запустити дію (Activity) програми відеосистеми, яка зробить фото. Після закінчення, фото надсилається до вашої програми і ви можете його використати. Для користувача все виглядало так, ніби камера являється частиною вашої програми.
Під час того, як система запускає компонент, вона запускає процес для даної програми (якщо процес ще не запущено) і створює класи, які необхідні для компоненту. Наприклад, якщо ваша програма запускає дію у програмі камери, яка створює фото, дана дія виконується в процесі, який не належить до вашої програми. Тому, на відміну від програм на у інших системах, програми Android не мають точки входу (не існує функції main).
Через те що система виконує кожну програму у окремому процесі з правами, які не дозволяють отримати доступ до інших програм, ваша програма не може прямо активувати компонент від іншої програми. Система Android, однак може. Отож, для активування компонент у іншій програмі, вам потрібно надіслати повідомлення, яке викриває ваш намір запустити певний компонент у системі. Система активує компонент для вас.
Активування компонентів
Три з чотирьох типів компонентів — дії, сервіси і отримувачі повідомлень, активуються за допомогою асинхронних викликів, які називаються намір (intent). Наміри зв'язують індивідуальні компоненти між собою під час виконання (ви можете думати про них, як про повідомлення від інших компонентів, які роблять запити на певні дії).
Інший тип компоненту — постачальник контенту, не викликається за допомогою намірів. Він скоріш, активізується коли до нього приходить запит від примірника ContentResolver. Отримувач контенту обробляє усі прямі трансакції за допомогою постачальника контенту, отож компонент, який виконує трансакції за допомогою постачальника, просто викликає метод з об'єкта ContentResolver. Це залишає рівень абстракції між постачальником контенту і компонентом (задля безпеки), який зробив запит на отримання певної інформації.
Існують декілька компонентів, які активують певні типи компонентів:
- Ви можете запустити дію (або змусити її виконувати іншу дію), передаючи об'єкт Intent до методу startAcrivity() або startAcrivityForResult(), (коли ви бажаєте, щоб дія повернула результат).
- Ви можете запустити сервіс (або надати нові інструкції для працюючого сервісу), передаючи об'єкт класу Intent до методу startService(). Або ж ви можете зв'язатись з сервісом передаючи об'єкт Intent до bindSerivce().
- Ви можете ініціювати загальносистемну подію, передаючи Intent до методу на подобі sendBroadcast(), sendOrderedBroadcast() або semdStickyBroadcast().
- Ви можете виконати запит до постачальника контенту, викликаючи метод query() над об'єктом класу ContentResolver.
Маніфест Файл
Перед тим, як ОС Android зможе запустити компонент програми, вона повинна отримати інформацію про те, що компонент існує з файлу AndroidManifest.xml. Ваша програма повинна оголосити усі наявні компоненти у даному файлі, який повинен бути в корені директорії проекту програми.
Маніфест-файл також грає декілька додаткових ролей:
- ідентифікує будь-які права користувача, які повинна мати програма, наприклад, доступ до Інтернету або доступ до читання/запису контактів користувача.
- Оголошує мінімальний рівень API, який необхідний для програми, спираючись на те, які інтерфейси API використовує програма.
- Оголошує необхідні компоненти або апаратне забезпечення, яке потребує програма, на подобі камери, сервіс Bluetooth, або екран з підтримкою індикації множинних доторків.
- Бібліотеки API, з якими повинна компонуватися програма (відмінні від фреймворку Android API), на подобі бібліотеки Google Maps і інші.
Оголошення компонентів
Головне завдання маніфест-файлу полягає у тому, щоб інформувати систему про наявні компоненти програми. Наприклад, маніфест-файл може оголосити дію наступним чином:
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:icon="@drawable/app_icon.png" ... >
<activity android:name="com.example.project.ExampleActivity"
android:label="@string/example_label" ... >
</activity>
...
</application>
</manifest>
У елементі , атрибут android:icon вказує на ресурси для іконок, які визначає програма.
У елементі , атрибут android:name вказує на повне ім'я класу потомка Activity і атрибут android:label вказує на рядок, який необхідно використовувати в якості видимої для користувача мітки для даної дії (activity).
Вам необхідно вказувати компоненти програми наступним чином:
- для елементів дій
- для сервісів
- елементи для отримувачів системних подій
- і елементи для вказування постачальників контенту.
Дії, сервіси і постачальники контенту, які ви включили у вихідний код, але не оголосили у маніфесті являються невидимими для системи і, відповідно, не можуть бути виконаними. Однак, отримувачі загальносистемних подій можуть оголошуватись як у маніфесті, так і створюватись динамічно у коді (в якості об'єктів BroadcastReceiver) і реєструватись за допомогою виклику registerReceiver().
Оголошення можливостей компонентів
Як було сказано вище, ви можете запускати дії (activities), сервіси і отримувачі подій за допомогою об'єктів класу Intent. Ви можете виконувати це, явно називаючи цільові компоненти (використовуючи ім'я класу компонента) у примірнику наміру. Однак, найкращий метод полягає у концепції неявних намірів. Неявний намір (intent) описує тип роботи для виконання і дозволяє системі знаходити компоненти на пристрої, які можуть виконувати роботу і запускати його. Якщо існує декілька компонентів, які виконують необхідну роботу, яка описана у об'єкті наміру, тоді користувач обирає, який з них використати.
Шлях за яким система визначає компоненти, які можуть відповісти на намір, визначається за допомогою порівняння намірів, які отримали фільтри намірів, розміщені у маніфестах інших програм на пристрої.
Коли ви оголошуєте дію у маніфесті вашої програми, ви можете включити фільтри намірів, які оголошують можливості дії, отож вона може відповісти на наміри від інших програм. Ви можете додати фільтр до компоненту, використовуючи елемент в якості потомка елементу оголошення компонента.
Наприклад, якщо ви створюєте поштовий клієнт, який містить дію (activity) для створення повідомлень, ви можете оголосити фільтр намірів для відповіді на намір “надсилання” (для надсилання нового повідомлення) на подобі:
<manifest ... >
...
<application ... >
<activity android:name="com.example.project.ComposeEmailActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<data android:type="*/*" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
В такому разі, коли інша програма створює намір з параметром дії ACTION_SEND і передає її у метод startActivity, система може розпочати дію від якої користувач надішле електронне повідомлення.
Оголошення залежностей програми
Конфігурація установлених систем Android на різних пристроях варіюється і не усі з них забезпечують одинакові можливості. Для того, щоб запобігти встановлення вашої програми на пристрої, які не мають потрібні функції і можливості, важливо, щоб ви явно оголосили профіль типів пристроїв, підтримувані вашою програмою, вказуючи програмне і апаратне забезпечення у вимогах до програми маніфест-файлу. Більшість з цих оголошень являються інформаційними і система не враховує їх, але зовнішні сервіси на подобі Google Play читають їх для забезпечення фільтрування для користувачів, під час пошуку програм з їхніх пристроїв.
Наприклад, якщо ваша програма вимагає присутність камери і використовує інтерфейс API, який був впроваджений в Android версії 2.1 (рівень API 7), вам необхідно оголосити дані вимоги у маніфест-файлі, як показано в наступному коді:
<manifest ... >
<uses-feature android:name="android.hardware.camera.any"
android:required="true" />
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
...
</manifest>
Тепер пристрої, які не мають вбудованих камер і утримують версію Android меншу ніж 2.1, не можуть встановити вашу програму з магазину Google Play.
Однак, ви також можете оголосити, що ваша програма використовує камеру, але не обов'язково вимагає її. У цьому випадку, ви повинні встановити атрибут required у значення false і перевіряти середовище на ознаки присутності вбудованої камери. Якщо вбудована камера відсутня на пристрої — вимкнути функції роботи з нею.
Ресурси пристрою
Програма для Android компонується не тільки з коду — вона вимагає ресурси, які відокремлені від коду, наприклад, зображення, аудіо-файли, і будь-що інше, що відповідає за візуальне представлення програми. Наприклад, ви можете визначити анімації, меню, стилі, кольори і макет дії (activity) інтерфейсу користувача за допомогою xml файлів. Використання ресурсів програми полегшує оновлення деяких характеристик вашої програми без модифікування коду, і забезпечуючи альтернативні ресурси — дозволяє вам оптимізувати вашу програму для деяких конфігурацій системи (на подобі різних мов і розмірів екрану).
Для кожного ресурсу, який ви включаєте у ваш Android проект, інструментарій SDK (Software Delevlopment Kit) визначає унікальний цілочисельний ідентифікатор, який ви можете використовувати для доступу до ресурсу з вашої програми або з інших ресурсів, які визначені в XML. Наприклад ваша програма містить файл зображення, який названий logo.png (збережений у каталозі res/drawable), інструментарій SDK згенерує ідентифікатор ресурсу під назвою R.drawable.logo, який ви можете використати для вказування на даний файл зображення, і вставляти його у інтерфейс користувача.
Один з найважливіших аспектів забезпечення ресурсами програми окремо від вашого вихідного коду програми полягає у можливості постачати альтернативні ресурси для різних конфігурацій пристроїв. Наприклад, визначаючи рядок UI у XML, ви можете перекласти його на іншу мову і зберегти дані рядки у окремих файлах. Після цього, спираючись на кваліфікатор мови, який ви додали до імені каталогу ресурсу (на подобі res/values-fr для французької) і налаштувань мови користувача, Android застосує відповідні налаштування мови до вашого інтерфейсу користувача.
Android підтримує велику кількість кваліфікаторів для ваших альтернативних ресурсів. Кваліфікатор являє собою короткий рядок символів, який ви включаєте у ім'я вашого каталогу ресурсу для визначення конфігурації пристрою, для яких ці ресурси будуть застосованими. Ви також часто повинні створювати різні макети для вашого інтерфейсу, в залежності від орієнтації і розміру екрану. Наприклад, коли екран пристрою має книжну орієнтацію (високу), ви можете забажати макет, у якому кнопки розміщені вертикально, але коли екран розміщений у альбомній орієнтації (широкий), кнопки повинні бути розміщеними горизонтально. Для зміни макету в залежності від орієнтації, ви можете визначити два різних макети і застосовувати відповідний кваліфікатор до кожного імені директорії в якому розміщується макет. Після цього система автоматично застосовує відповідні макети в залежності від поточної орієнтації екрану.
Рекомендуємо також для прочитання статтю "Перша програма “Привіт, Світ!” на Android".