Android курс в Технополисе 2022

В этом уроке мы создадим простейшее Android приложение, состоящее из одного экрана, на котором отображается текст приветствия. Несмотря на простоту, в процессе создания этого приложения мы познакомимся с несколькими важными базовыми концепциями, без которых в Android разработке просто никуда! Поэтому, будьте внимательны :)

Создание проекта

Запустите Android Studio и выберите “New Project” на приветственном экране.

На следующем экране “New Project” вам предлагается сразу при создании проекта добавить в приложение первый дефолтный экран (Activity – это программный компонент, приблизительно соответствующий отдельному экрану приложения). В нашем Hello World приложении вам следует выбрать “No Activity”, то есть не добавлять Activity в приложение. Мы сделаем это позже вручную – это очень просто, а предлагаемые варианты это всего лишь шаблоны для Activity с различными стандартными элементами пользовательского интерфейса.

На следующем экране вам надо заполнить несколько полей.

Прежде всего, это Name – название приложения как видит его пользователь – это может быть произвольная строка. Android Studio может использовать name для названия директории, в которой будет создан проект, а так же как часть Package name. Поэтому, если вы используете в name какие-нибудь экзотические символы (например, кириллицу), то обязательно проверьте правильность Save location и Package name.

Следующее поле – это Package name. Принято использовать доменный стиль записи. Например, можно написать com.github.<username> или ru.<last name>.<first name>.

Save location – путь к директории создаваемого проекта. Укажите любое удобное вам место, главное – это должна быть новая директория, в которой будет лежать сам проект, а не его родительская папка. (Например, /Users/yuriy.dorofeev не годится, а /Users/yuriy.dorofeev/HelloWorld – годится).

Package name – уникальный идентификатор приложения с точки зрения операционной системы Android, который используется в технических целях везде, где надо идентифицировать приложение. Например, на одном устройстве не могут быть установлены два приложения с одинаковым package name. Также package name используется как основной идентификатор в магазинах приложений. Поэтому package name надо выбирать правильно – оно должно быть уникальное, понятное, адекватное. Обычно package name похоже на доменное имя наоборот с добавлением названия приложения, например com.github.<username>.helloworld. Package ID или Application ID являются синонимами Package name на Android. А вот понятие Java пакета технически никак не связано с Package name, хотя часто в Android приложении используются имена Java пакетов, совпадающие с Package name.

Language – основной язык разработки. Писать приложения под Android можно как на Java, так и на Kotlin. Мы советуем начинать все новые приложения писать на Kotlin.

Minimum SDK – минимальная поддерживаемая версия Android для вашего приложения. Для приложения Hello World можно оставить дефолтное значение (на момент написания статьи это API 21: Android 5.0), однако для реальных приложений к выбору минимальной поддерживаемой версии Android надо подходить более ответственно.

Чем выше минимальная поддерживаемая версия, тем проще разрабатывать приложения – вы сможете легко использовать новые фичи, появившиеся только в поздних версиях Android, и вам не надо будет думать о поддержке старых устройств, но, с другой стороны, ваше приложение не сможет работать на более старых устройствах, и, таким образом, потенциальная аудитория приложения будет меньше. Если же вы хотите, чтобы ваше приложение работало у максимального количества пользователей, то вам надо выбирать более древнюю минимальную версию Android, но в таком случае в процессе разработки вы можете столкнуться с проблемами совместимости со старыми устройствами. Выбор минимальной поддерживаемой версии Android – это всегда компромисc между сложностью разработки и потенциальным размером аудитории. Если нажать на Help me choose, то вы увидите список версий Android с числами охвата аудитории для каждой из версий (если эта версия будет выбрана в качестве минимально поддерживаемой).

На момент написания этой статьи для большинства приложений разумным выбором будет API 21: Android 5.0.

На этом начальная конфигурация проекта завершена – жмем Finish, и Android Studio создаст наш проект. Если вы недавно установили Android Studio и впервые создаете проект, то, возможно, вам придется немного подождать, пока скачаются дополнительные инструменты и зависимости. Дождитесь сообщения “BUILD SUCCESSFUL” в нижней панели во вкладке Build – это значит, что инициализация проекта завершена, он даже уже собрался, и можно начинать работать.

Возможные проблемы на данном этапе – отсутствие соединения с Интернетом, невозможность скачать необходимые зависимости. Если в нижней панели во вкладке Build или Sync появились какие-то сообщения об ошибках, то устраните их причину и обновите проект нажатием на кнопку “Sync Project with Gradle Files” в верхней панели инструментов.

Структура проекта

Сразу после создания нового пустого проекта мы можем посмотреть на его содержимое в панели проекта, которая обычно отображается слева. Если по какой-то причине этой панели нет, нажмите cmd-1 (на MacOS) – это keyboard shortcut для открытия панели проекта. Сейчас там есть два пункта: app и Gradle Scripts – раскройте их.

Gradle Scripts содержит файлы, относящиеся к системе сборки проекта (Gradle – это опенсорсная система автоматической сборки, при помощи которой собираются Android приложения).

app – это модуль приложения. Любой Android проект состоит из модулей, в простейшем случае – из одного модуля, внутри которого находится весь исходный код и ресурсы приложения. Внутри app можно увидеть следующие разделы:

Внутри manifests находится файл AndroidManifest.xml – это файл, в котором указаны основные параметры приложения и его структура с точки зрения операционной системы Android.

Раздел java содержит исходный код приложения (на языке Java или Kotlin), который делится на три части: основной код (сейчас там пусто), код юнит тестов (test) и код инструментальных тестов (androidTest). AndroidStudio всегда генерирует заглушки для тестов и инструментальных тестов при создании нового проекта или нового модуля. Нас они сейчас не интересуют, поэтому их можно удалить. Выберите пакеты test и androidTest и удалите их.

Наконец, папка res содержит ресурсы приложения – всякие полезные штуки, не являющиеся исполняемым кодом: изображения, тексты, верстка и т.п. Обратите внимание, что Android ресурсы в папке res не являются обычными Java ресурсами (которые загружаются при помощи java.lang.ClassLoader.getResource()) – это совершенно особенная тема в Android, которая обладает большими возможностями (но об этом позже).

Я не просто так называл некоторые элементы внутри app “разделами”, а не “папками” – дело в том, что они не являются папками в файловой системе. Панель проекта имеет несколько режимов отображения. По умолчанию используется режим Android – в нем файлы сгруппированы таким вот способом, и этот способ не соответствует их размещению в файловой системе. Если вы хотите видеть, как файлы проекта расположены на самом деле, переключите панель проекта в режим Project (выпадающий список в верхней части панели проекта), в котором отображается реальная файловая структура проекта.

Создание экрана Hello World

Теперь мы добавим в приложение один экран, на котором будет отображаться приветствие. Основным компонентом, соответствующим экрану в UI приложения, является Activity. (В русскоязычной официальной документации почему-то пишут операция – это неудачный перевод. Не говорите операция – вас не поймут). В коде activity – это класс, наследующий от базового класса android.app.Activity.

Создайте класс HelloWorldActivity в дефолтном пакете проекта (при создании нового проекта автоматически генерируется дефолтный пакет с названием, совпадающим с Package name приложения в папке app/src/main/java/). Далее унаследуем класс от AppCompatActivity это наследник Activity позволяющий безопасно работать с новыми фичами андроида на старых версиях ОС.

Прежде чем мы напишем какой-то полезный код внутри HelloWorldActivity, добавим запись о ней в манифест приложения. Обратите внимание: название класса HelloWorldActivity подсвечено желтым в коде – это Android Studio подсказывает нам, что activity HelloWorldActivity не прописана в манифесте. Таковы правила – все activity приложения должны быть прописаны в манифесте для того, чтобы операционная система знала, из каких экранов состоит наше приложение, и как их запускать.

Манифест приложения находится в файле app/src/main/AndroidManifest.xml – откройте этот файл и добавьте в него такой код внутри application элемента:

<activity
    android:name=".HelloWorldActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Элемент activity в Android манифесте декларирует activity внутри приложения в качестве точки входа в UI приложения из операционной системы. В этих нескольких строчках есть несколько интересных моментов:

Теперь попробуем запустить наше Hello World приложение – для этого можно нажать кнопку Run (треугольник типа Play в верхней панели инструментов) или выбрать Run ‘app’ в меню.

Создание эмулятора

Для того что бы создать новый эмулятор, нужно открыть Device Manager.

На скриншоте выше уже есть некоторое количество эмуляторов. В вашем случае этот список будет пуст. Для того, что бы создать новый эмулятор, нажмите на кнопку “Create device”.

Здесь мы можем выбрать тип устройства, которое мы хотим использовать. Выберем Phone и Pixel 2. Нажимаем “Next”.

В окне “AVD” выберите S, API Level 31 (здесь, возможно, вам потребуется предварительно скачать соответствующий системный образ). Нажимаем Next.

Вводим имя эмулятора и нажимаем Next. Будет создан эмулятор устройства Pixel 2 с операционной системой Android версии 12.0, который появится в списке устройств, на которых можно запустить приложение. Таким же образом вы можете создавать сколько угодно разных эмуляторов с разными типами устройств и версиями Android, которые можно использовать одновременно (только имейте в виду, что каждый эмулятор занимает несколько гигабайт дискового пространства).

Когда эмулятор создан, мы можем запустить на нём наше приложение Hello World.

Вскоре после запуска вы увидите белый экран в эмуляторе – это и есть activity Hello World. Вполне ожидаемый результат для пустого класса без единой строчки кода? На самом деле можно задаться вопросом, почему экран белый? Он мог бы быть черным или вообще прозрачным (тогда бы мы не смогли отличить пустое приложение от домашнего экрана смартфона). Где-то ведь должен быть код, который рисует этот белый цвет на весь экран? Но мы этот код не писали… Ответ на этот вопрос – дефолтная тема activity, в которой задан белый цвет фона окна. Пока так, без объяснений :)

Создание UI для экрана Hello World

Теперь, когда простейший скелет приложения готов, можно добавить код, который будет вместо пустого белого экрана отображать текст приветствия. Для этого переопределим один важный метод в классе HelloWorldActivity. Добавьте такой код в пустое тело класса HelloWorldActivity (либо воспользуйтесь диалогом переопределения методов, который вызывается Ctrl-O):

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

Метод onCreate является основной точкой входа в Activity – он вызывается системой каждый раз, когда создается новая activity. В этом методе можно создать и инициализировать все необходимые компоненты UI, которые будут отображаться в окне activity. Для определения UI в Android используются файлы верстки (layout файлы или лэйауты), которые являются частью ресурсов приложения. Это XML файлы, в которых описывается, как будет устроена и как будет выглядеть какая-то часть UI приложения. Приложение в рантайме при помощи специальных методов загружает лэйауты из ресурсов и использует их для создания UI.

Значит, для отображения текста приветствия на экране HelloWorldActivity нам нужно в ресурсах приложения создать файл верстки, в котором будет описано, как это приветствие выглядит. Ресурсы приложения лежат в папке src/main/res в модуле app (если в проекте несколько модулей, то каждый модуль имеет свои ресурсы), внутри которой находятся директории с ресурсами разного типа. Файлы верстки лежат в директории layout. Если такой директории нет в вашем проекте, то её нужно создать – для этого выберите пункт New / Android Resource Directory в контекстном меню папки res.

Затем в диалоге создания директории ресурсов выберите Resoucre Type layout и нажмите OK.

Эти действия абсолютны эквивалентны просто созданию папки layout внутри res в файловой системе – вы можете сделать это в командной строке при помощи команды mkdir, и эффект будет точно такой же. Диалог в Android Studio удобен тем, что он показывает, какие имена директорий имеют значение, и какие у них могут быть модификаторы.

Теперь в папке layout создадим файл верстки экрана Hello World – выберите New / Layout resource file в контекстном меню папки layout,

введите имя activity_hello_world (есть распространенное соглашение именно так именовать файлы верстки для Activity – сначала слово activity, потом имя класса), а в поле Root element введите FrameLayout (он лучше подходит для нашего простого примера).

Android Studio создаст файл activity_hello_world.xml и откроет его в редакторе. Редактор лэйаутов в Android Studio имеет два режима: Design для “визуального” редактирования, Split для написания разметки и ее параллельного просмотра и Code для работы только с разметкой. Рекомендую сразу забыть про Design и переключиться в Split – профессиональные разработчики пользуются только им или Code.

В исходном коде верстки вы увидите автоматически сгенерированный корневой элемент FrameLayout. FrameLayout – это имя класса android.widget.FrameLayout из Android SDK, который наследует от android.view.ViewGroup, который в свою очередь наследует от android.view.View. Убедиться в этом можно, если навести курсор на имя элемента FrameLayout и нажать Cmd-B (это переход к исходному коду в Android Studio) – вы увидите исходный код класса FrameLayout.

View является самым базовым фундаментальным элементом, из которого строится UI в Android. Каждый экземпляр View соответствует какой-то прямоугольной области в пользовательском интерфейсе, в котором что-то отображается и происходит взаимодействие с пользователем. Все View на экране организованы в иерархическую структуру типа дерево. ViewGroup – это особый тип View, который может находиться в узле дерева, то есть содержать в себе другие View. Файлы верстки определяют иерархическую структуру дерева View при помощи иерархической структуры XML элементов. Каждый XML элемент соответствует какому-то View, полное Java имя класса которого используется в качестве имени XML элемента. Для стандартных классов View из Android SDK можно использовать простое имя класса (как наш FrameLayout).

Итак, автоматически сгенерированный файл верстки activity_hello_world.xml содержит описание дерева View, которое состоит из одного единственного корневого узла FrameLayout. FrameLayout – это простейший контейнер (рамка), внутри которой могут отображаться другие View. Мы добавим в него TextView – специальный тип View для отображения текста.

Отредактируйте activity_hello_world.xml так, чтобы весь его код выглядел следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Hello, World!" />

</FrameLayout>

Атрибут text у TextView, наверное, не требует объяснений, а остальные атрибуты заслуживают особого внимания. Здесь мы видим атрибуты layout_width, layout_height и layout_gravity. Вообще, все атрибуты, имя которых начинается на layout_, определяют размеры и расположение View. layout_width и layout_height определяют ширину и высоту.

Ключевое слово match_parent для ширины или высоты говорит о том, что размер View должен совпадать с его родителем. FrameLayout является корневым элементом лэйаута, и его родитель определяется тем, как мы используем этот лэйаут. Поскольку мы собираемся использовать наш лэйаут для экрана Hello World, родителем FrameLayout можно условно считать весь экран. То есть, FrameLayout примет размеры целого экрана.

Ключевое слово wrap_content для ширины или высоты говорит о том, что View должен принять минимально необходимый размер для того, чтобы в нем можно было отобразить его содержимое. В нашем лэйауте TextView примет размеры прямоугольной области, содержащей текст “Hello, World!”.

Атрибут layout_gravity определяет, как View располагается внутри своего родителя. В данном случае TextView будет располагаться по центру своего родителя FrameLayout, то есть по центру экрана.

Из всех атрибутов, которые могут быть у XML элементов в файле верстки, самые важные – это layout_width и layout_height. Они являются обязательными. Если эти атрибуты не указать, то приложение упадет при попытке загрузить файл верстки.

Вернемся к коду HelloWorldActivity и его методу onCreate, в котором мы должны создать UI экрана Hello World. Сейчас в этом методе есть только вызов super.onCreate(), который необходим для того, чтобы activity была создана правильно. Добавьте одну строчку кода после super.onCreate:

setContentView(R.layout.activity_hello_world)

Эта строчка кода означает буквально следующее: загрузить из файла верстки activity_hello_world иерархию View и использовать её в качестве контента, отображаемого в UI нашей activity. Метод setContentView является методом класса Activity, и один из его вариантов принимает в качестве аргумента ID ресурса, соответствующего файлу верстки, который надо использовать. ID ресурсов имеют тип int, и они автоматически генерируются для всех ресурсов приложения во время сборки. R.layout.activity_hello_world – это автоматически сгенерированная константа, соответствующая ресурсу activity_hello_world в папке layout, которую можно использовать в коде приложения.

Запустите приложение снова – в этот раз вы увидите сообщение Hello World в центре экрана

Строковые ресурсы и локализация

Для того чтобы всё было сделано правильно, осталось сделать одно небольшое исправление. Откройте файл верстки activity_hello_world и посмотрите на атрибут text у TextView: он подсвечен желтым цветом – это Android Studio намекает, что что-то с ним не так. Если навести на него курсор, то можно увидеть сообщение о том, что не так: студия говорит, что строка “Hello World!” захардкожена, и так делать не надо. Действительно, строки в Android (как и практически везде) не принято хардкодить, а принято хранить в ресурсах. Для этого есть специальный тип ресурсов – string.

Откройте файл res/values/strings.xml – сейчас там должна быть всего одна строчка app_name, которая была автоматически сгенерирована при создании проекта. Добавьте еще одну строчку для нашего сообщения:

<string name="hello_world">Hello, World!</string>

Теперь вместо захардкоженной строки в файле верстки activity_hello_world можно использовать ссылку на ресурс hello_world:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="@string/hello_world" />

Синтаксис @string/hello_world является XML аналогом Java констант, используемых для ID ресурсов в коде. В Kotlin коде ID этой строки выглядел бы так:

R.string.hello_world

Кроме того, что теперь текст не захардкожен в коде, и его использование и изменение теперь лучше организовано, есть еще одна хорошая причина хранить строки в ресурсах приложения. Эта причина – локализация. Android предоставляет механизм локализации, основанный на системе ресурсов, который позволяет показывать разные варианты текста на разных языках в зависимости от того, какой язык выбран в качестве основного в настройках устройства, на котором запущено приложение.

В качестве демонстрации системы локализации добавим в наше приложение перевод Hello World на русский язык. Для этого создадим альтернативный ресурс hello_world, который будет использоваться в русской локали.

Альтернативные ресурсы

Понятие альтернативных ресурсов – это общее понятие на Android, которое применяется к любым типам ресурсов (не только к строчкам) и означает, что для некоторого ресурса существуют его альтернативные версии, которые используются при каких-то особых условиях вместо дефолтной версии. Альтернативные версии ресурсов имеют такой же ID, как и основной дефолтный ресурс, и код, который ссылается на этот ID может не думать о том, какая версия ресурса будет использована на самом деле – Android выбирает нужную версию сам автоматически.

Альтернативные ресурсы хранятся в отдельных директориях внутри папки res, которые отличаются от обычных директорий с ресурсами тем, что к их имени добавляется квалификаторы (qualifier), которые соответствуют условию, при котором ресурсы в этой директории будут использоваться. Для создания директории для альтернативных строк можно воспользоваться диалогом создания Android Resource Directory – в этот раз следует выбрать Resource type values (потому что оригинальные строковые ресурсы лежат в директории values), и добавить квалификатор Locale, выбрав при этом язык Russian и регион Any Region.

Android Studio создаст директорию values-ru внутри папки res. Если вы точно знаете, как должна называться директория с альтернативными ресурсами, вы можете просто создать её руками в файловой системе – это будет иметь такой же эффект. Диалог же удобен тем, что вы можете увидеть все возможные варианты – например, список языков и регионов, которые можно использовать.

Создайте внутри директории values-ru файл strings.xml со следующим содержимым:

<resources>
    <string name="hello_world">Здравствуй, Мир!</string>
</resources>

Здесь определен альтернативный ресурс hello_world – это то же самое имя, которое мы уже использовали для основного ресурса. Значение же ресурса отличается – это перевод на русский язык дефолтного значения. Это всё, что нужно сделать для работы системы локализации – мы просто добавили перевод одной строки, и не изменили ничего в коде приложения, где эта строка используется.

Чтобы проверить, как это работает, перезапустите приложение на эмуляторе. По умолчанию в эмуляторе установлен английский язык в качестве основного. Чтобы сменить язык, зайдите в системные настройки в раздел System / Languages & Input / Language и там добавьте русский язык и перетащите его на первое место в списке, чтобы он стал основным языком интерфейса. После этого переключитесь обратно в приложение Hello World – вы увидите сообщение “Здравствуй, Мир!” на русском языке. При этом название приложения Hello World, которое можно увидеть, например, под иконкой приложения на домашнем экране смартфона, осталось неизменным – потому что строковый ресурс app_name не имеет альтернативного ресурса в русской локали.

Итоги

Hello World – это простейшее приложение, которое вообще можно сделать на Android (не считая пустого экрана), но в процессе его создания мы много узнали о базовых технологиях Android разработки, которые используются во всех проектах. Вот краткий список того, с чем мы только что познакомились: