Как пользоваться Android Studio


Арина Мурашева Эксперт в Java, Kotlin, Android, SQL, проектировании информационных систем.
Android-разработчица такси Maxim и ментор курса «Android-разработчик» Арина Мурашева подробно рассказывает, как установить и использовать Android Studio и как собирать и отлаживать приложения.

Освойте профессию «Android-разработчик»
Для чего используется Android Studio?
Android Studio — это IDE (интегрированная среда разработки) для работы с платформой Android. Она позволяет разрабатывать приложения для смартфонов, планшетов, часов, телевизоров и других устройств на этой ОС. Я использую Android Studio, потому что это официальная среда разработки, которую поддерживает Google. Она основана на IntelliJ IDEA от компании JetBrains, чьи продукты я люблю и использую еще со студенческих времен. В Android Studio те же горячие клавиши и интерфейс, что и в других продуктах JetBrains, поэтому для меня эта среда самая привычная и удобная.
Установка Android Studio
16 месяцев
Android-разработчик
Запускайте приложения и игры для Android
4 790 ₽/мес 7 983 ₽/мес

Когда нужно принимать важные решения, связанные с будущим, профессией и самоопределением, бывает страшно. Но важный шаг к избавлению от страха — озвучить его. Сделайте это, ответив на пять коротких вопросов. Ссылка в конце статьи.
1. Установка Java SDK
Установите Java SDK независимо от того, планируете вы разрабатывать на Java или Kotlin. Для этого перейдите на официальный сайт Oracle в раздел Downloads и скачайте нужную версию Java SDK. Для разных проектов могут понадобиться разные версии, но если вы не знаете, какая нужна, — скачивайте последнюю.
2. Установка и настройка Android Studio
В отличие от многих инструментов разработки, за Android Studio не нужно платить. Чтобы скачать Android Studio, перейдите на официальный сайт для разработчиков Android и нажмите Download, согласитесь с условиями использования и нажмите Download Android Studio. После завершения скачивания запустите установочный файл и начните процесс установки. Сначала выберите путь установки Android Studio и Android SDK. Оставьте пути по умолчанию или выберите свои.
Если у вас уже установлена старая версия Android Studio, то первое окно установщика будет выглядеть как на скриншоте ниже. При этом процесс установки будет немного отличаться, однако в этой статье рассматривается только первичная установка Android Studio.
После этого несколько раз нажмите Next, оставляя все параметры по умолчанию, пока не начнется установка. После завершения установки Android Studio должна запуститься автоматически. Если нет, то ярлык программы вы сможете найти в меню «Пуск» или на рабочем столе. При первом запуске Android Studio нужно будет ее настроить. Сначала студия спросит, нужно ли импортировать настройки с прошлой версии. Так как это первая установка студии, то сохраненных настроек у вас нет. Оставьте второй вариант и нажмите OK.
После этого завершите настройку и скачайте необходимые компоненты с помощью Setup Wizard, который открывается после нажатия OK в предыдущем окне.
Нажмите Next и перейдите к выбору типа установки компонентов Android Studio.
Если вам не нужна кастомная настройка компонентов, выберите Standard и нажмите Next. После этого установщик сообщит, что необходимо загрузить несколько компонентов для завершения установки. Нажмите Finish и подождите, пока все компоненты загрузятся и распакуются. После завершения этого процесса снова станет доступна кнопка Finish. Нажмите на нее, после чего появится экран приветствия Android Studio. 

Станьте Android-разработчиком — работайте в штате, на фрилансе или запускайте собственные приложения
Как использовать Android Studio
Работа в Android Studio похожа на работу в большинстве современных IDE. Однако, как и везде, здесь есть свои нюансы. Далее мы разберем основы работы в Android Studio. Для начала необходимо создать проект в Android Studio. На приветственном экране нажмите Create New Project, после этого вы увидите экран с шаблонами устройств и Activity (это класс, в котором реализуют логику экрана приложения). Для начала можно выбрать Phone and Tablet (телефоны и планшеты) и No Activity либо Empty Activity. Разница в том, что в первом случае вам нужно будет реализовать первую Activity с нуля, а во втором студия самостоятельно создаст готовый редактируемый шаблон. После выбора нажмите Next и увидите окно настроек будущего проекта. Название проекта (Name) в Android Studio может быть любым и даже содержать пробелы. А вот имя пакета (Package Name) должно быть уникальным, если вы собираетесь опубликовать приложение в Google Play. Что еще можно выбрать: расположение проекта (Save Location), язык (Language), который вы собираетесь использовать (Java или Kotlin), и минимальную поддерживаемую SDK (Minimum SDK). Минимальная поддерживаемая SDK — это самая ранняя версия операционной системы Android, в которой приложение может работать. Если вы меняете расположение файлов проекта, то не забудьте создать папку, которая будет содержать ваш проект. Обратите внимание, что в названии не должно быть пробелов. Язык здесь можно выбрать любой, потому что в проекте доступны и Java, и Kotlin. А вот минимальную поддерживаемую Android SDK выбирайте внимательно. Студия подсказывает, какое количество устройств на сегодняшний день поддерживают ту или иную SDK. Старайтесь выбрать минимальное значение, чтобы как можно больше устройств могли успешно работать с вашим приложением в Android Studio. Но учтите, что чем ниже минимальная SDK, тем больше трудностей будет возникать при разработке.
Структура проекта Android

Если в предыдущем шаге вы выбрали шаблон Empty Activity, то при создании проекта студия сгенерирует и структуру файлов проекта. Так выглядит пустой, только что созданный проект в Android Studio. Он содержит 2 корневые папки: app и Gradle Scripts. Папка app включает 3 подпапки: manifests (содержит файлы конфигураций приложения), java (содержит исходный код приложения) и res (содержит файлы ресурсов — картинок, стилей, размерностей и т.д.). AndroidManifest.xml в папке manifests содержит информацию о пакетах и компонентах приложения. Этот файл важен для работы приложения Android, так как именно в нем прописаны разрешения приложения на использование компонентов системы Android. Также в нем определяется, как будут запускаться компоненты приложения.
Читайте также Кто такой Android-разработчик?
- Папка drawable содержит файлы с изображениями.
- В папке layout нужно располагать xml-файлы, используемые для создания интерфейса приложения.
- Папка mipmap хранит значки приложения.
- Папка values хранит xml-файлы со значениями строк, цветов, тем, стилей.
Папка Gradle Scripts содержит скрипты для автоматизации сборки проекта.
Папка .idea не видна на скриншоте, но если изменить конфигурацию Android на Project, то она появится. Эта папка нужна для настройки метаданных проекта в Android Studio.
Редактор xml
Для редактирования xml-файлов в Android Studio встроен удобный инструмент. Он позволяет не только редактировать код xml-файлов, но и видеть изменения в режиме реального времени с помощью визуального представления. В этом же визуальном представлении можно редактировать xml-файлы.
Чтобы посмотреть работу этого редактора, откройте файл activity_main.xml, сгенерированный Android Studio. Кстати, если ваш проект уже разросся и искать файлы неудобно, то нажмите клавишу Shift быстро два раза, и откроется окно поиска по файлам проекта. Начните вводить туда название нужного файла, а затем выберите его из списка. Как видно на анимации, необязательно вводить слова полностью — достаточно первых букв.
По умолчанию открывается только редактор кода.

Чтобы открыть визуальный редактор, нажмите кнопку Split в верхнем правом углу, чтобы отобразить оба представления рядом. Или кнопку Design, чтобы открыть только визуальное представление.
Gradle
Android Studio выполняет сборку приложения с использованием системы Gradle. Он значительно упрощает сборку проекта из большого количества файлов в apk-файл, который можно установить на Android-устройстве.
Хочу поделиться лайфхаком, который выручал меня не раз. Если проект перестал собираться по непонятной причине, скорее всего, это связано с gradle. В таком случае в меню выберите Build, а затем опцию Clear Project.
Сборка и отладка приложения
После того как вы добавили первую функциональность в свое приложение, начните отлаживать его (запускать и проверять работоспособность всех функций). Лучше делать это на устройстве Android.
Для этого подключите устройство Android к компьютеру через USB. При этом убедитесь, что на телефоне включена отладка по USB в параметрах разработчика.
Чтобы включить параметры разработчика, в настройках своего телефона найдите пункт «Номер сборки» (обычно находится в «Сведениях об устройстве») и нажмите на него быстро семь раз. Далее перейдите в параметры разработчика и включите отладку по USB.
После этого подключите телефон через USB к компьютеру и увидите название своего устройства в верхней панели Android Studio — у меня это Samsung. Обратите внимание, на телефоне могут появиться уведомления, где нужно разрешить отладку с данного компьютера.

Затем нажмите на кнопку Run (зеленый треугольник), и приложение запустится на вашем телефоне.
Если приложение «упало» (завершило работу, когда не должно было) или возникли какие-то другие ошибки — данные вы увидите на вкладке Logcat (внизу).

В панели настроек Logcat можно выбрать устройство, на котором производится отладка, отлаживаемый процесс и поставить фильтр на сообщения, которые хотите видеть в Logcat. Обычно сообщения об ошибках и так заметны — они выделяются красным, — но если хотите видеть только их, то поставьте фильтр Error.

Отладка приложения на виртуальных устройствах
Устройств на Android так много, что невозможно протестировать код на каждом из них. Здесь на помощь приходят виртуальные устройства, доступные для скачивания из Android Studio.
Чтобы создать виртуальное устройство, откройте AVD Manager (Android Virtual Device Manager) и начните создание желаемого устройства.

Для создания нового устройства нажмите кнопку Create Virtual Device. Затем выберите устройство (модель телефона).
После нажмите Next и переходите к выбору системы Android, которая будет установлена на устройство. Если ранее вы не устанавливали ни одной эмулированной системы, то ее нужно будет скачать. У меня уже скачан Android Q.
После скачивания нажмите Next, затем Finish, и создание виртуального устройства завершено.
Чтобы запустить приложение на созданном устройстве, выберите его в списке устройств и нажмите кнопку Run.
Главное — практика
По-настоящему освоить Android Studio получится только самостоятельно в процессе практики. Дополнительно рекомендую изучить горячие клавиши в Android Studio (как двойное нажатие Shift для поиска по файлам).
Android-разработчик
Освойте программирование на Java и Kotlin, мобильную разработку и UX/UI, разработайте свое приложение для Android. Центр карьеры поможет с резюме и подготовкой к собеседованию. Программа подойдет для новичков
How to find the logs on Android Studio?
I have tried to import my project to Android Studio and I got this error. I need to know where I can get the logs.
Consult IDE log for more details (Help | Show Log)
18.6k 31 31 gold badges 67 67 silver badges 75 75 bronze badges
asked Nov 5, 2013 at 8:49
5,203 6 6 gold badges 47 47 silver badges 65 65 bronze badges
Did you try View > Tool Windows > Android?
Nov 5, 2013 at 8:51
There is an option in your Toolbar to check your logs by enabling (DDMS i.e. android icon) or else in bottom you can check Android>>Devices | logcat.
Nov 5, 2013 at 9:00
@PankajKumar I want to know where to find logs.how this question will be duplicate?
Nov 5, 2013 at 9:02
@Gru it doesnot show anything about y this project has not been integrated?
Nov 5, 2013 at 9:05
In my Windows 10 «Help/Show Log In Explorer» goes to «This Computer» view and it does not go to the directory where the logs are. The logs can be found manually in C:\Users\
Apr 6, 2018 at 6:03
16 Answers 16
On toolbar -> Help Menu -> Show log in Explorer or Show log in Finder (for Mac users).
It opens log folder, where you can find all logs.

answered Nov 6, 2013 at 10:26
Gabriele Mariotti Gabriele Mariotti
327k 98 98 gold badges 900 900 silver badges 851 851 bronze badges
@Alston is it a good reason to downvote an answer of 3 years ago? In 2.2.3 the Help is in the same position. Check the toolbar, last entry on the right «Help» then «show log in explorer».
Jan 17, 2017 at 12:20
For mac users, that would be Show Log in Finder
Jan 3, 2018 at 12:44
I got the same error, however the log shows no valuable information yet: 2021-12-07 14:32:10,627 [ 156388] ERROR — intellij.openapi.progress.Task — OS: Linux 2021-12-07 14:32:10,628 [ 156389] ERROR — intellij.openapi.progress.Task — Last Action: 2021-12-07 14:32:10,722 [ 156483] INFO — cState$SyncStateUpdaterService — stopTrackingTask(RESOLVE_PROJECT:0) 2021-12-07 14:32:10,726 [ 156487] WARN — e.project.sync.GradleSyncState — Gradle sync failed: Sync failed: reason unknown (55 s 334 ms)
Dec 7, 2021 at 11:36
It works only if you have some project opened (at least it’s true for my Android Studio Chipmunk | 2021.2.1 Patch 2), so you have to open some project or create at least blank project first
Android Studio для NDK под Windows

На днях я обнаружил, что версия Android Studio неуклонно стремится к единице, в связи с чем задумался об изучении этого инструмента. Чтобы не было скучно, я решил поделиться своим опытом и собранными граблями в виде статьи-туториала.
Сразу хочу оговориться, что я не являюсь гуру Android-разработки, поэтому каких-либо откровений в тексте вы не найдете. Зато тут есть пошаговая инструкция по установке и настройке Android Studio под Windows и созданию простейшего проекта с использованием Android NDK.
Также заранее предупреждаю: статья получилась большой и очень подробной (честно, сам не ожидал), даже несмотря на то, что я почти все скриншоты и некоторые листинги кода спрятал под спойлеры.
На момент написания последней версией Android Studio была 0.8.1, для последующих версий необходимые действия могут отличаться от нижеописанных (очень надеюсь, что в лучшую сторону).
Установка и настройка Android Studio
1. Необходимо установить JDK (Java Development Kit) и JRE (Java Runtime Environment).
Раньше Android SDK поддерживал только JDK версии 6, но теперь это в прошлом. Поддерживается 7 и даже 8 (по крайней мере, именно 8-ю версию я указал в качестве JAVA_HOME и в настройках Android Studio, и никаких проблем не испытал).
JRE же нужен для запуска самой студии. У меня она использует версию 7.
Скачать JDK и JRE версий больше 6 можно с сайта Oracle.
- Зайти в Панель управления\Система и безопасность\Система, выбрать слева Дополнительные параметры системы, в открывшемся диалоге найти кнопку Переменные среды.
- Создать системную или пользовательскую переменную JAVA_HOME и указать для нее путь к JDK. У меня указан вот такой путь: C:\Program Files\Java\jdk1.8.0_05.
Если вы по каким-либо причинам нуждаетесь в 6 версии JDK
- Скачать Java EE 6 с сайта Oracle.
- Установить его. В комплекте есть JDK 6.
- В качестве JAVA_HOME в этом случае нужно указать путь к JDK из Java EE, по умолчанию это C:/glassfish3/jdk.
2. Если у вас установлен Android SDK.
В комплекте с Android Studio идет свой Android SDK. И, если вы хотите использовать именно его, то в некоторых случаях может случиться странное. Например, у меня при обновлении SDK через SDK Manager часть файлов записывалась в старую папку, и возникли проблемы, когда я эту папку удалил. Скорее всего это произошло из-за того, что в реестре хранился ключ с путем к старой папке. Поэтому имеет смысл почистить реестр. Для этого нужно запустить regedit.exe и найти HKEY_LOCAL_MACHINE\Software\Android SDK Tools для 32-битных машин либо HKEY_LOCAL_MACHINE\Software\Wow6432Node\Android SDK Tools для 64-битных машин и удалить Android SDK Tools. Если в реестре вашей системы таких ключей нет, то все в порядке.
Если у вас установлена переменная среды ANDROID_SDK_HOME и вы хотите, чтобы она указывала на старую установку, то, по идее, это не должно стать проблемой, так как при настройке Android Studio мы укажем ей путь к SDK. Проблемы могут возникнуть, если эту переменную использует какое-либо из приложений, входящих в состав Android SDK.
3. Теперь переходим к установке Android Studio.
Нужно скачать Android Studio для вашей системы с официальной страницы и установить ее. По умолчанию, если выбрать «Установить только для меня» ставится в \Users\\AppData\Local\Android\android-studio\, иначе ставится в \Program FIles (x86)\Android\android-studio\. Можно выбрать и другую папку.
После установки запускаем Android Studio.
Видим вот такой диалог

- Проверяем обновления и, при необходимости, обновляемся (для этого нажмите на Check в нижней части окна)
- Заходим в Configure->SDK Manager (на всякий случай: SDK Manager — это не часть Android Studio, а утилита из Android SDK) и устанавливаем то, что вам необходимо. Если вы не знаете, что необходимо, то лучше установить все, что он предложит.
Вот что он установил у меня
Как это сделать

нужно зайти в Configure->Settings->Appearance:
Скриншот

Создание проекта
1. New Project
Жмем New Project.
Появляется вот такой диалог

- Имя проекта (я оставил по умолчанию: My Application)
- Домен компании, по умолчанию .example.com, в моем случае markedone.example.com
- Имя пакета тоже можно отредактировать, нажав на Edit справа. По умолчанию генерируется из имени проекта и домена компании и выглядит как com.example..com.example.markedone.myapp.
- Путь, куда будет сохранен проект. Я указал свою папку для всяких тестовых проектов.
2. Form Factors
В этом диалоге выбираем целевые платформы и API.
Диалог выглядит так

Здесь я все оставил по умолчанию: Phone and Tablet и 4.0.3 IceCreamSandwich. Если API для каких-то платформ не установлен, выдается сообщение Not Insatlled. Например, как видно на скриншоте, у меня не установлены библиотеки для Google Glass (сделать это можно через SDK Manager).
Также обратите внимание на Help me choose, прикольная штука
Если нажать Help me choose, то откроется вот такой интересный диалог
Он содержит информацию по охвату устройств при выборе той или иной версии API. Прямоугольники версий API кликабельны, справа будет выведен список доступного в них функционала. Например, для предлагаемого по умолчанию Ice Cream Sandwich’а:
3. Add Activity
На следующем экране нам предлагается выбрать Activity

Естественно, я не смог пройти мимо Fullscreen Activity и выбрал ее. Вы можете выбрать другую Activity, но в этом случае у нас будут отличаться исходники на Java, и вам придется самостоятельно добавлять вызов нативного метода из Java (впрочем, в этом нет ничего сложного).
Делаем выбор, нажимаем Next.
Появляется следующий диалог

- Activity Name — имя класса, я оставил по умолчанию: FullscreenActivity.
- Layout Name — имя layout, для редактора UI, также оставляем по умолчанию.
- Title — по умолчанию предлагается FullscreenActivity, я поставил пробел: Fullscreen Activity.
В итоге должен открыться проект

Сборка и запуск
1. Сборка проекта
Запускаем сборку через меню: Build->Make Project (для пунктов меню указаны иконки и горячие клавиши, так что с ними будет несложно разобраться).
У меня при первой сборке возникла ошибка:
Произошло это в файле MyApplication/app/build.gradle
Для того, чтобы понять в чем дело, достаточно навести курсор на подчеркнутую строку:
Все просто, здесь указана версия 19, а у нас установлена только 20, да и в настройках проекта мы указали 20 как целевую. Просто поменяем цифру:
Как видно, студия на этом не успокоилась, и предлагает установить еще более новую версию. Но нам сейчас это не нужно.
Снова запускаем Build->Make Project. На этот раз у меня все собралось. Надеюсь, у вас тоже.
2. Настройка виртуального устройства
Для того чтобы запустить программу в эмуляторе, нужно настроить виртуальное устройство. Заходим в Tools->Android->AVD Manager (это, как и SDK Manager, утилита из Android SDK). Нам нужна первая вкладка, Android Virtual Device, она и открыта по умолчанию. Справа находим кнопку Create. и нажимаем ее.
Появится диалог настройки виртуального устройства


- AVD Name — имя виртуального устройства, я ввел TestPhone. Дальше я, правда, выбрал планшет, но уже не стал менять название.
- Device — различные предустановленные настройки устройства, значение выбирается из доступных в выпадающем списке, я выбрал 7» WSVGA (Tablet) (1024 x 600: mdpi).
- Target — целевая версия API, доступны только те, которые есть в SDK. Установить их можно через SDK Manager.
W в названии означает Wear, версия для носимых устройств (часы и прочее). Так как мы в настройках проекта выбирали Tablet&Phone, то нам нужен другой пункт: Android L (Preview) — API Level L.
- CPU/ABI — платформа, я выбрал ARM (armeabi-v7a).
- Keyboard — тут, думаю, все понятно.
- Skin — как я понял, внешний вид устройства, я выбрал значение, соответствующее установленному значению Device: WSVGA.
- Front Camera и Back Camera — наличие камер.
- Memory Options — оперативная память.
- Internal Storage — жесткий диск устройства.
- SD Card — думаю, понятно.
- Emulation options: Snapshot — позволяет эмулятору сохранять свое состояние между запусками, Use Host GPU — позволяет использовать видеокарту компьютера для OpenGL ES. Последнюю опцию я включил, но OpenGL — приложение у меня впоследствии упало на этом эмуляторе при старте. Наверное, из-за ARM vs x86_64.
Внизу диалога выводится, какую ошибку вы допустили при настройке. Например, в имени устройства нельзя вводить пробелы, а некоторые поля обязательны для заполнения. Когда внизу нет надписи — все введено верно. Жмем OK.
Устройство появилось в списке

Пара слов о вкладке Device Definitions
На ней заданы доступные устройства (те, которые потом отображаются в выпадающем списке Device при создании нового виртуального устройства). Чтобы создать новое устройство, нужно нажать на кнопку Create Device. и озаботиться заполнением следующего диалога:
Закрываем AVD Manager и возвращаемся в главное окно Android Studio.
3. Запуск на эмуляторе
Выполняем Run->Run ‘app’.
Придется подождать, пока произойдет сборка проекта для запуска.
В конце концов, появится окно выбора устройства
Здесь единственный доступный вариант для выбора — это наше виртуальное устройство. Он нам сразу предложен, так что просто жмем OK.
Запускается эмулятор, довольно долго

Можно открыть Tools->Android->Android Device Monitor (утилита из Android SDK), чтобы увидеть логи с эмулятора. Он должен автоматически подцепить виртуальное устройство и сразу начать выводить лог.
Android Device Monitor

А вот приложение после запуска эмулятора у меня с первого раза не открылось, пришлось еще раз нажать Run->Run ‘app’.
Появился немного изменившийся диалог

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

А если на приложение тапнуть, то выглядит оно так

Это не поведение системы, обработка клика происходит в приложении (файл FullscreenActivity.java):
// Set up the user interaction to manually show or hide the system UI. contentView.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View view) < if (TOGGLE_ON_CLICK) < mSystemUiHider.toggle(); >else < mSystemUiHider.show(); >> >);
После запуска, Android Studio предложила мне выключить Android Device Monitor, для того чтобы интегрировать вывод прямо в IDE.
Вот как выглядит интеграция

4. Запуск в Debug-режиме
Run->Debug ‘app’
Снова уже знакомый нам диалог

Ждем, пока запустится приложение и приконнектится дебаггер. Я поставил точку останова при нажатии на кнопку Dummy Button.
Android Studio в дебаге

Немного раздражает отсутствие панельки со всякими Step Into, Step Out etc.
Все это находится в меню Run

5. Запуск на 4.0.3
В процессе создания и запуска проекта вы, наверное, заметили, что мы создали приложение, совместимое с версией 4.0.3, но запускали его только на самой последней версии Android. Сейчас мы это исправим. Для этого нужно установить версию 4.0.3 через Tools->Android->SDK Manager.
Необходимое отмечено галочками на скриншоте

Это SDK Platform, ARM EABI v7a System Image и Intel x86 Atom System Image. На самом деле, мы запускали эмулятор ARM, и Intel нам сейчас ставить не обязательно. Я его поставил сугубо потому, что он установлен и для Android L.
Теперь создадим еще одно устройство для новой старой версии Android (или же вы можете отредактировать старое).
Настройки нового устройства

Запускаем (Run->Run ‘app’).
В диалоге выбираем новое устройство для запуска

И смотрим, как выглядит новый эмулятор — явно брутальнее.
Запуск

Полноэкранный режим

После нажатия

5. Запуск на устройстве
Перед тем как перейти к работе с NDK, давайте запустим проект на реальном устройстве. Я буду запускать на телефоне
Huawei Ascend G300 с Android 4.0.3

Первое, что нужно сделать, это установить adb-драйвер. У меня с этим все довольно просто, драйвер находится прямо на телефоне, единственное, что нужно сделать, это воткнуть шнур в компьютер, зайти в примонтировавшийся диск и запустить исполняемый файл, который и установит adb-драйвер. Для других устройств все может быть сложнее. Например, для планшета Prestigio мне в свое время пришлось прописывать Vendor ID в специальный файл (чтобы использовался стандартный драйвер от Google), для Samsung нужен их собственный Kies, был отдельный драйвер для HTC и так далее. В общем, вам придется самостоятельно разобраться, как установить драйвер для вашего устройства.
После того как драйвер был установлен, нужно на устройстве разрешить отладку по USB. У меня на телефоне для этого нужно зайти в Настройки->Для разработчиков->Отладка по USB. Но для разных устройств, а также сборок и версий Android, расположение этого пункта меню может отличаться.
Теперь телефон будет находиться Android SDK, а разрабатываемые приложения будут устанавливаться. Однако, для Huawei это еще не все: с телефона не идут логи, нужно их включить.
Как включить логи на Huawei
Набрать в качестве телефонного номера: *#*#2846579#*#*
Появится сервисное меню.
Перейти в ProjectMenu->Background Setting->Log Setting
Открыть Log switch и установить там ON.
Открыть Log level setting и установить необходимый вам уровень логирования (я поставил verbose).
Перезагрузить телефон.
Теперь можно запускать приложение на устройстве: Run->Run ‘app’
В диалоге выбора устройства появилось реальное устройство

Запускаемся на телефоне.
Результат запуска.
Приложение в портрете:
- На полный экран

- После нажатия

Приложение в ландшафте:
- На полный экран

- После нажатия

Установка и настройка Android NDK
1. Установка NDK
Android SDK, как мы уже выяснили, входит в комплект Android Studio, а вот NDK — нет. Скачиваем NDK, подходящий для вашей системы, отсюда. Распаковываем архив и кладем в какую-нибудь папку, например, в D:\ndk, так, чтобы файл ndk-build.cmd лежал прямо в ней. Важно: необходимо, чтобы в пути к NDK не было пробелов.
2. Добавим переменную ANDROID_NDK_HOME
Заходим в Панель управления\Система и безопасность\Система, выбираем слева Дополнительные параметры системы, в открывшемся диалоге нажимаем кнопку Переменные среды. Создаем переменную с именем ANDROID_NDK_HOME и значением D:\ndk (путь к вашей NDK).
Альтернативно, вместо указания глобальной переменной можно прописать путь к ndk в файле local.properties вашего проекта (прямо в корневой папке: MyApplication\local.properties). Содержимое файла будет выглядеть примерно так (обратите внимание на двойные бэкслеши, так как для Windows это критично):
## This file is automatically generated by Android Studio. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file should *NOT* be checked into Version Control Systems, # as it contains information specific to your local configuration. # # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. sdk.dir=C:\\Users\\\\AppData\\Local\\Android\\android-studio\\sdk ndk.dir=D:\\ndk
Не верьте дисклеймеру про «ваши изменения будут выкинуты», в данном случае это не так. Обратите внимание, что этот файл рекомендуется исключать из-под контроля версий, так как он содержит только локальную для пользователя информацию. Для разнообразия в этом нам не соврали. Ну и, само собой, это изменение никак не повлияет на другие Ваши проекты. При установленной ANDROID_NDK_HOME прописывать путь в local.properties необязательно.
3. Установим необходимую версию Android API
Зайдите в NDK\platforms (у меня это D:\ndk\platforms) и посмотрите максимальную версию доступных API. В моем случае максимальная версия 19. Но при этом в SDK у нас установлены только версии 20 и 15. Так что заходим в SDK Manager и скачиваем SDK Platform версии 19, иначе ничего не соберется.
Что надо скачать

4. Настроим gradle для работы с NDK
Информацию я брал из сэмплов, скачать их можно здесь, в самом низу страницы. Я скачивал сэмплы для версии 0.11. В качестве основного примера я брал ndkSanAngeles.
Как запустить ndkSanAngeles

После того, как сэмплы скачаны, их нужно распаковать. Затем нужно открыть проект ndkSanAngeles. Для Android Studio проектом является папка, так что открывать надо именно ее. Для того этого выполняем File->Open, либо, если вы в Welcome диалоге, Open Project. Ищем папку ndkSanAngeles через диалог открытия файла.
После открытия проекта стоит обратить взор на файл build.gradle. Вот его оригинал:
buildscript < repositories < mavenCentral() >dependencies < classpath 'com.android.tools.build:gradle:0.11.0' >> apply plugin: 'android' android < compileSdkVersion 19 buildToolsVersion '19.1.0' defaultConfig < ndk < moduleName "sanangeles" cFlags "-DANDROID_NDK -DDISABLE_IMPORTGL" ldLibs "GLESv1_CM", "dl", "log" stl "stlport_static" >// This actual the app version code. Giving ourselves 1,000,000 values versionCode = 123 > buildTypes.debug.jniDebugBuild true productFlavors < x86 < ndk < abiFilter "x86" >// this is the flavor part of the version code. // It must be higher than the arm one for devices supporting // both, as x86 is preferred. versionCode = 3 > arm < ndk < abiFilter "armeabi-v7a" >versionCode = 2 > mips < ndk < abiFilter "mips" >versionCode = 1 > fat < // fat binary, lowest version code to be // the last option versionCode = 0 >> // make per-variant version code applicationVariants.all < variant ->// get the single flavor def flavorVersion = variant.productFlavors.get(0).versionCode // set the composite code variant.mergedFlavor.versionCode = flavorVersion * 1000000 + defaultConfig.versionCode > >
А вот измененная версия, чтобы проект собирался у меня:
buildscript < repositories < mavenCentral() >dependencies < classpath 'com.android.tools.build:gradle:0.12.+' >> apply plugin: 'android' android < compileSdkVersion 19 buildToolsVersion '20.0.0' defaultConfig < ndk < moduleName "sanangeles" cFlags "-DANDROID_NDK -DDISABLE_IMPORTGL" ldLibs "GLESv1_CM", "dl", "log" stl "stlport_static" >// This actual the app version code. Giving ourselves 1,000,000 values versionCode = 123 > buildTypes.debug.jniDebugBuild true productFlavors < x86 < ndk < abiFilter "x86" >// this is the flavor part of the version code. // It must be higher than the arm one for devices supporting // both, as x86 is preferred. versionCode = 3 > arm < ndk < abiFilter "armeabi-v7a" >versionCode = 2 > mips < ndk < abiFilter "mips" >versionCode = 1 > fat < // fat binary, lowest version code to be // the last option versionCode = 0 >> // make per-variant version code applicationVariants.all < variant ->// get the single flavor def flavorVersion = variant.productFlavors.get(0).versionCode // set the composite code variant.mergedFlavor.versionCode = flavorVersion * 1000000 + defaultConfig.versionCode > >
- О несовпадении версии плагина gradle (classpath ‘com.android.tools.build:gradle:0.11.0’) будет сказано при попытке сборки и предложен правильный номер версии. У меня это 0.12.+.
- compileSdkVersion 19 остается, так как это максимальная версия для текущего NDK.
- buildToolsVersion изменился на 20. Установленные версии можно посмотреть в SDK Manager, там же можно установить другие.
В нашем проекте нужно выбрать правильный файд build.gradle, так как здесь их два. Дело в том, что MyApplication — это проект, а app — это модуль проекта (или подпроект), и у них build.gradle для каждого свой. Сначала рассмотрим файл проекта
MyApplication->build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript < repositories < jcenter() >dependencies < classpath 'com.android.tools.build:gradle:0.12.+' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files >> allprojects < repositories < jcenter() >>
Из комментариев в коде явно следует, что нам нужен файл модуля
MyApplication->app->build.gradle
apply plugin: 'com.android.application' android < compileSdkVersion 20 buildToolsVersion "20.0.0" defaultConfig < applicationId "com.example.markedone.myapp" minSdkVersion 15 targetSdkVersion 20 versionCode 1 versionName "1.0" >buildTypes < release < runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' >> > dependencies < compile fileTree(dir: 'libs', include: ['*.jar']) // You must install or update the Support Repository through the SDK manager to use this dependency. //compile 'com.android.support:support-v4:19.+' compile 'com.android.support:support-v4:20.+' >
Настроим его для работы с NDK, используя в качестве «донора» build.gradle из ndkSanAngeles.
Для начала, заменим
compileSdkVersion 20
на
compileSdkVersion 19
так как NDK ограничен версией 19.
В defaultConfig мы добавим настройки ndk, а также заменим targetSdkVersion на 19:
defaultConfig < applicationId "com.example.markedone.myapp" minSdkVersion 15 targetSdkVersion 19 versionCode 1 versionName "1.0" ndk < moduleName "myapp" cFlags "-DANDROID_NDK" ldLibs "log" stl "stlport_static" >>
- moduleName — имя модуля, будет использовано для именования *.so файла
- cFlags — флаги C
- ldLibs — библиотеки, которые вы хотите подключить к нативному коду
- stl — версия библиотеки STL
buildTypes < release < runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' >debug.jniDebugBuild true >
Теперь добавим productFlavors. Здесь мы указываем, какие собранные *.so библиотеки включать в сборку под конкретную архитектуру. Таким образом, *.apk собранный для arm будет содержать версию библиотеки только для arm, под x86 — для x86 и так далее. Этот кусок полностью скопирован с ndkSanAngeles. Объяснение значений versionCode из комментариев: для x86 ставим максимальное значение versionCode, так как если устройство поддерживает и x86 и arm, то сборка x86 предпочтительнее (видимо, так как у нее большая версия, то установлена будет именно она), а минимальный versionCode прописывается для fat (по идее это должен быть «толстый» *.apk, содержащий сразу все возможные версии библиотек).
productFlavors < x86 < ndk < abiFilter "x86" >// this is the flavor part of the version code. // It must be higher than the arm one for devices supporting // both, as x86 is preferred. versionCode = 3 > arm < ndk < abiFilter "armeabi-v7a" >versionCode = 2 > mips < ndk < abiFilter "mips" >versionCode = 1 > fat < // fat binary, lowest version code to be // the last option versionCode = 0 >>
«Собираем» значение versionCode для каждого из вариантов сборки:
// make per-variant version code applicationVariants.all < variant ->// get the single flavor def flavorVersion = variant.productFlavors.get(0).versionCode // set the composite code variant.mergedFlavor.versionCode = flavorVersion * 1000000 + defaultConfig.versionCode >
Наконец, последняя секция, dependencies. Если помните, здесь мы меняли compile ‘com.android.support:support-v4:19.+’ на compile ‘com.android.support:support-v4:20.+’, чтобы собирать с единственной установленной у нас версией библиотеки. Теперь придется поменять обратно на 19.
dependencies < compile fileTree(dir: 'libs', include: ['*.jar']) // You must install or update the Support Repository through the SDK manager to use this dependency. compile 'com.android.support:support-v4:19.+' >
Полный листинг измененного файла build.gradle
apply plugin: 'com.android.application' android < compileSdkVersion 19 buildToolsVersion "20.0.0" defaultConfig < applicationId "com.example.markedone.myapp" minSdkVersion 15 targetSdkVersion 19 versionCode 1 versionName "1.0" ndk < moduleName "myapp" cFlags "-DANDROID_NDK" ldLibs "log" stl "stlport_static" >> buildTypes < release < runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' >debug.jniDebugBuild true > productFlavors < x86 < ndk < abiFilter "x86" >// this is the flavor part of the version code. // It must be higher than the arm one for devices supporting // both, as x86 is preferred. versionCode = 3 > arm < ndk < abiFilter "armeabi-v7a" >versionCode = 2 > mips < ndk < abiFilter "mips" >versionCode = 1 > fat < // fat binary, lowest version code to be // the last option versionCode = 0 >> // make per-variant version code applicationVariants.all < variant ->// get the single flavor def flavorVersion = variant.productFlavors.get(0).versionCode // set the composite code variant.mergedFlavor.versionCode = flavorVersion * 1000000 + defaultConfig.versionCode > sourceSets < main < jni.srcDirs = ['src/main/jni', 'src/main/jni/'] >> > dependencies < compile fileTree(dir: 'libs', include: ['*.jar']) // You must install or update the Support Repository through the SDK manager to use this dependency. compile 'com.android.support:support-v4:19.+' >
5. Создаем папку jni
В папке jni мы будем сохранять C/C++ файлы. Этого от нас ожидает NDK. Папку нам нужно создать в MyApplication/app/src/main. Это можно сделать прямо из Android Studio, причем, двумя способами.
Во-первых, можно кликнуть правой кнопкой на main и просто создать папку через
New->Directory

Во вторых, можно воспользоваться специальным пунктом меню
New->Folder->JNI Folder

Он запускает визард создания папки
В первом диалоге мы выбираем, для какой части модуля будет создана папка jni, а во втором можно изменить ее расположение.
6. Добавим C++ файлы
Визарда для C++ файлов нет, поэтому для создания файла мы кликаем правой кнопкой на папке jni и выбираем
New->File

Для начала создадим заголовочный файл myapp.h:
#pragma once #include #ifdef __cplusplus extern "C" < #endif JNIEXPORT jstring JNICALL Java_com_example_markedone_myapp_FullscreenActivity_stringFromJNI(JNIEnv* env, jclass clazz); #ifdef __cplusplus >#endif
Описание
- #pragma once — вместо стандартной (#ifndef/#define/#endif) защиты от повторного включения. Сейчас #pragma once понимается большинством C++ компиляторов.
- #include — включаем заголовок JNI, чтобы можно было использовать типы, объявленные там.
- #ifdef __cplusplus . #endif — код внутри будет скомпилирован только в C++ (но не в C).
- extern «C» < . >— избавляемся от name mangling (что это и почему, хорошо описано тут).
- JNIEXPORT jstring JNICALL Java_com_example_markedone_myapp_FullscreenActivity_stringFromJNI(JNIEnv* env, jclass clazz); — объявление функции, которую будем реализовывать.
Разберем это объявление подробнее.- JNIEXPORT необходимо для грамотной линковки.
- JNICALL для правильного соглашения о вызове.
- jstring — тип возвращаемого значения функции, в данном случае это строка, совместимая со строкой Java.
- Java_com_example_markedone_myapp_FullscreenActivity_stringFromJNI — имя функции, состоит из:
Java — язык, который вызывает.
com_example_markedone_myapp — это id приложения (com.example.markedone.myapp).
FullscreenActivity — имя класса Java, который содержит объявление метода, представляющего нативную функцию.
stringFromJNI — собственно, имя функции (таким оно будет в Java). - JNIEnv* env, jclass clazz — обязательные параметры, передающиеся из Java.
JNIEnv* env — указатель на объект, представляющий из себя JNI-окружение.
jclass clazz — класс, которому принадлежит объявление нативного метода в Java. Здесь нужно оговориться, что jclass clazz — это для статического нативного (static native) метода. Для нестатического метода будет нужно писать jobject obj .
Теперь создадим файл реализации, myapp.cpp. В нем мы напишем следующий код:
#include #include #include "myapp.h" JNIEXPORT jstring JNICALL Java_com_example_markedone_myapp_FullscreenActivity_stringFromJNI(JNIEnv* env, jclass clazz) < std::string tag("GREETING"); std::string message("Hello from C++!"); __android_log_print(ANDROID_LOG_INFO, tag.c_str(), "%s", message.c_str()); std::string jniMessage("Hello from JNI!"); return env->NewStringUTF(jniMessage.c_str()); >Описание
- #include — подключаем лог, ради которого мы даже добавили библиотеку (ldLibs «log»)
- #include — для std::string, который мы используем для проверки наличия STL.
#include «myapp.h» — подключаем наш заголовочный файл.
JNIEXPORT jstring JNICALL Java_com_example_markedone_myapp_FullscreenActivity_stringFromJNI(JNIEnv* env, jclass clazz) < . >— реализуем функцию, объявленную в «myapp.h».
std::string tag(«GREETING»); std::string message(«Hello from C++!»); — создаем строки для вывода в лог.
__android_log_print(ANDROID_LOG_INFO, tag.c_str(), «%s», message.c_str()); — вывод в лог. Обратите внимание, что необходимо указывать 4 параметра: тип сообщения в логе, тэг, формат строки, и, наконец, само сообщение.
std::string jniMessage(«Hello from JNI!»); — строка, которую мы будем передавать в Java.
return env->NewStringUTF(jniMessage.c_str()); — возвращаемое значение, при помощи JNIEnv создаем jstring из C-строки. Обратите внимание, что нам не нужна конструкция вида (*env)-> , так как мы пишем на C++, а не на C.
7. Добавим вызов нативной функции из Java
Открываем файл MyApplication/app/src/main/java/com.example.markedone.myapp.FullscreenActivity. На самом деле, у него расширение java, а com, example, markedone и myapp — это папки, но Android Studio это скрывает.
Содержимое файла
package com.example.markedone.myapp; import com.example.markedone.myapp.util.SystemUiHider; import android.annotation.TargetApi; import android.app.Activity; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.view.MotionEvent; import android.view.View; /** * An example full-screen activity that shows and hides the system UI (i.e. * status bar and navigation/system bar) with user interaction. * * @see SystemUiHider */ public class FullscreenActivity extends Activity < /** * Whether or not the system UI should be auto-hidden after * milliseconds. */ private static final boolean AUTO_HIDE = true; /** * If is set, the number of milliseconds to wait after * user interaction before hiding the system UI. */ private static final int AUTO_HIDE_DELAY_MILLIS = 3000; /** * If set, will toggle the system UI visibility upon interaction. Otherwise, * will show the system UI visibility upon interaction. */ private static final boolean TOGGLE_ON_CLICK = true; /** * The flags to pass to . */ private static final int HIDER_FLAGS = SystemUiHider.FLAG_HIDE_NAVIGATION; /** * The instance of the for this activity. */ private SystemUiHider mSystemUiHider; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_fullscreen); final View controlsView = findViewById(R.id.fullscreen_content_controls); final View contentView = findViewById(R.id.fullscreen_content); // Set up an instance of SystemUiHider to control the system UI for // this activity. mSystemUiHider = SystemUiHider.getInstance(this, contentView, HIDER_FLAGS); mSystemUiHider.setup(); mSystemUiHider .setOnVisibilityChangeListener(new SystemUiHider.OnVisibilityChangeListener() < // Cached values. int mControlsHeight; int mShortAnimTime; @Override @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) public void onVisibilityChange(boolean visible) < if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) < // If the ViewPropertyAnimator API is available // (Honeycomb MR2 and later), use it to animate the // in-layout UI controls at the bottom of the // screen. if (mControlsHeight == 0) < mControlsHeight = controlsView.getHeight(); >if (mShortAnimTime == 0) < mShortAnimTime = getResources().getInteger( android.R.integer.config_shortAnimTime); >controlsView.animate() .translationY(visible ? 0 : mControlsHeight) .setDuration(mShortAnimTime); > else < // If the ViewPropertyAnimator APIs aren't // available, simply show or hide the in-layout UI // controls. controlsView.setVisibility(visible ? View.VISIBLE : View.GONE); >if (visible && AUTO_HIDE) < // Schedule a hide(). delayedHide(AUTO_HIDE_DELAY_MILLIS); >> >); // Set up the user interaction to manually show or hide the system UI. contentView.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View view) < if (TOGGLE_ON_CLICK) < mSystemUiHider.toggle(); >else < mSystemUiHider.show(); >> >); // Upon interacting with UI controls, delay any scheduled hide() // operations to prevent the jarring behavior of controls going away // while interacting with the UI. findViewById(R.id.dummy_button).setOnTouchListener(mDelayHideTouchListener); > @Override protected void onPostCreate(Bundle savedInstanceState) < super.onPostCreate(savedInstanceState); // Trigger the initial hide() shortly after the activity has been // created, to briefly hint to the user that UI controls // are available. delayedHide(100); >/** * Touch listener to use for in-layout UI controls to delay hiding the * system UI. This is to prevent the jarring behavior of controls going away * while interacting with activity UI. */ View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() < @Override public boolean onTouch(View view, MotionEvent motionEvent) < if (AUTO_HIDE) < delayedHide(AUTO_HIDE_DELAY_MILLIS); >return false; > >; Handler mHideHandler = new Handler(); Runnable mHideRunnable = new Runnable() < @Override public void run() < mSystemUiHider.hide(); >>; /** * Schedules a call to hide() in [delay] milliseconds, canceling any * previously scheduled calls. */ private void delayedHide(int delayMillis) < mHideHandler.removeCallbacks(mHideRunnable); mHideHandler.postDelayed(mHideRunnable, delayMillis); >>Добавим следующий код в класс FullscreenActivity:
static < System.loadLibrary("myapp"); >private static native String stringFromJNI();Здесь сначала идет загрузка библиотеки, а затем объявление метода stringFromJNI, который соответствует нашей функции в C++. Обратите внимание, что он объявлен как static (это влияет на то, что (jclass или jobject) будет в качестве второго параметра C++-функции) и native. Реализовывать native-метод не нужно, мы это уже сделали в C++, а остальное за нас сделает JNI.
Теперь мы, в общем-то, уже можем вызвать нашу функцию. Если вы, как и я, выбрали FullscreenActivity, то у нас есть Dummy Button, который, по сути, ничего не делает. И даже уже есть touch listener, пусть и не самый лучший (он будет вызываться много раз, пока палец на экране), но, чтобы не плодить лишний код, используем его.
Для начала добавим в список импорта:
import android.widget.Button;
чтобы можно было нормально работать с кнопкой.Найдем следующий код:
View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() < @Override public boolean onTouch(View view, MotionEvent motionEvent) < if (AUTO_HIDE) < delayedHide(AUTO_HIDE_DELAY_MILLIS); >return false; > >;и добавим несколько строк перед return false .
View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() < @Override public boolean onTouch(View view, MotionEvent motionEvent) < if (AUTO_HIDE) < delayedHide(AUTO_HIDE_DELAY_MILLIS); >final String message = stringFromJNI(); final Button button = (Button)findViewById(R.id.dummy_button); final String actualText = button.getText().toString(); if(message.equals(actualText)) < button.setText("Dummy Button"); >else < button.setText(message); >return false; > >;Описание добавленного кода
- final String message = stringFromJNI(); — получаем строку из C++. Вызов нативного метода — то, ради чего все и затевалось.
- final Button button = (Button)findViewById(R.id.dummy_button); — находим объект кнопки.
- final String actualText = button.getText().toString(); — вытаскиваем текущий текст кнопки.
- if(message.equals(actualText)) — сравниваем строку, полученную из C++, с текстом кнопки.
- button.setText(«Dummy Button»); — если одинаковы, меняем текст кнопки на Dummy Button.
- button.setText(message); — если различаются, то меняем на текст, полученный из C++.
Полный листинг класса измененного класса
package com.example.markedone.myapp; import com.example.markedone.myapp.util.SystemUiHider; import android.annotation.TargetApi; import android.app.Activity; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.view.MotionEvent; import android.view.View; import android.widget.Button; /** * An example full-screen activity that shows and hides the system UI (i.e. * status bar and navigation/system bar) with user interaction. * * @see SystemUiHider */ public class FullscreenActivity extends Activity < static < System.loadLibrary("myapp"); >private static native String stringFromJNI(); /** * Whether or not the system UI should be auto-hidden after * milliseconds. */ private static final boolean AUTO_HIDE = true; /** * If is set, the number of milliseconds to wait after * user interaction before hiding the system UI. */ private static final int AUTO_HIDE_DELAY_MILLIS = 3000; /** * If set, will toggle the system UI visibility upon interaction. Otherwise, * will show the system UI visibility upon interaction. */ private static final boolean TOGGLE_ON_CLICK = true; /** * The flags to pass to . */ private static final int HIDER_FLAGS = SystemUiHider.FLAG_HIDE_NAVIGATION; /** * The instance of the for this activity. */ private SystemUiHider mSystemUiHider; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_fullscreen); final View controlsView = findViewById(R.id.fullscreen_content_controls); final View contentView = findViewById(R.id.fullscreen_content); // Set up an instance of SystemUiHider to control the system UI for // this activity. mSystemUiHider = SystemUiHider.getInstance(this, contentView, HIDER_FLAGS); mSystemUiHider.setup(); mSystemUiHider .setOnVisibilityChangeListener(new SystemUiHider.OnVisibilityChangeListener() < // Cached values. int mControlsHeight; int mShortAnimTime; @Override @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) public void onVisibilityChange(boolean visible) < if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) < // If the ViewPropertyAnimator API is available // (Honeycomb MR2 and later), use it to animate the // in-layout UI controls at the bottom of the // screen. if (mControlsHeight == 0) < mControlsHeight = controlsView.getHeight(); >if (mShortAnimTime == 0) < mShortAnimTime = getResources().getInteger( android.R.integer.config_shortAnimTime); >controlsView.animate() .translationY(visible ? 0 : mControlsHeight) .setDuration(mShortAnimTime); > else < // If the ViewPropertyAnimator APIs aren't // available, simply show or hide the in-layout UI // controls. controlsView.setVisibility(visible ? View.VISIBLE : View.GONE); >if (visible && AUTO_HIDE) < // Schedule a hide(). delayedHide(AUTO_HIDE_DELAY_MILLIS); >> >); // Set up the user interaction to manually show or hide the system UI. contentView.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View view) < if (TOGGLE_ON_CLICK) < mSystemUiHider.toggle(); >else < mSystemUiHider.show(); >> >); // Upon interacting with UI controls, delay any scheduled hide() // operations to prevent the jarring behavior of controls going away // while interacting with the UI. findViewById(R.id.dummy_button).setOnTouchListener(mDelayHideTouchListener); > @Override protected void onPostCreate(Bundle savedInstanceState) < super.onPostCreate(savedInstanceState); // Trigger the initial hide() shortly after the activity has been // created, to briefly hint to the user that UI controls // are available. delayedHide(100); >/** * Touch listener to use for in-layout UI controls to delay hiding the * system UI. This is to prevent the jarring behavior of controls going away * while interacting with activity UI. */ View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() < @Override public boolean onTouch(View view, MotionEvent motionEvent) < if (AUTO_HIDE) < delayedHide(AUTO_HIDE_DELAY_MILLIS); >final String message = stringFromJNI(); final Button button = (Button)findViewById(R.id.dummy_button); final String actualText = button.getText().toString(); if(message.equals(actualText)) < button.setText("Dummy Button"); >else < button.setText(message); >return false; > >; Handler mHideHandler = new Handler(); Runnable mHideRunnable = new Runnable() < @Override public void run() < mSystemUiHider.hide(); >>; /** * Schedules a call to hide() in [delay] milliseconds, canceling any * previously scheduled calls. */ private void delayedHide(int delayMillis) < mHideHandler.removeCallbacks(mHideRunnable); mHideHandler.postDelayed(mHideRunnable, delayMillis); >>17. Собираем и запускаем проект
Сначала Build->Make Project. На этом этапе собирается Java-часть.
Затем Run->Run ‘app’. А вот здесь, перед стартом приложения, будет происходить сборка C++ части. Если в ней будут какие-то ошибки, то об этом будет выведено сообщение. Если ошибок нет, то появится стандартный диалог выбора устройства, и, после нажатия OK приложение запустится.Работа на реальном устройстве


Вывод сообщения в лог

Заключение
В целом, мне Android Studio понравилась. Интеграция Android SDK выполнена довольно плотно, иногда даже забываешь, что это запускаются отдельные программы. Есть всякие интересные плюшки, такие, как Help me choose. Понравилась новая система сборки — Gradle, — но тут же и недостаток: по ней очень мало информации.
Также, видно, что поддержка NDK еще сыровата, но прослеживается движение в этом направлении. Очень надеюсь, что они все-таки сделают полноценную поддержку C++-разработки.
P.S. Дебага C++ кода пока не обнаружено.
Logcat

В Android SDK входит набор инструментов, предназначенных для отладки. Самый важный инструмент при отладке — это LogCat (очень красивое название, которое можно перевести как Логичный Кот). Он отображает сообщения логов (журнал логов), рассылаемые при помощи различных методов.
В студии версии Electric Eel обновили Logcat. Все старые примеры работают, но появились дополнительные возможности.
Рассмотрим на примере стандартное применение Logcat. Очень часто программисту нужно вывести куда-то промежуточные результаты, чтобы понять, почему программа не работает. Особо хитрые временно размещают на экране текстовую метку и выводят туда сообщение при помощи метода textView.setText(«Здесь был Васька»). Но есть способ лучше. В Android есть специальный класс android.util.Log для подобных случаев.
Класс android.util.Log позволяет разбивать сообщения по категориям в зависимости от важности. Для разбивки по категориям используются специальные методы, которые легко запомнить по первым буквам, указывающие на категорию:
- Log.e() — ошибки (error)
- Log.w() — предупреждения (warning)
- Log.i() — информация (info)
- Log.d() — отладка (degub)
- Log.v() — подробности (verbose)
- Log.wtf() — очень серьёзная ошибка! (What a Terrible Failure!, работает начиная с Android 2.2)
- Log.meow() — когда жрать дадут? (MEOW!) Недокументированный метод, используйте на свой страх и риск. Работает не на всех устройствах
В первом параметре метода используется строка, называемая тегом. Обычно принято объявлять глобальную статическую строковую переменную TAG в начале кода:
private val TAG = "MyApp"
private static final String TAG = "MyApp";Некоторые в сложных проектах используют следующий вариант, чтобы понимать, в каком классе происходит вызов:
private val TAG = this.javaClass.simpleName
private static final String TAG = this.getClass().getSimpleName();Далее уже в любом месте вашей программы вы вызываете нужный метод журналирования с этим тегом:
Log.i(TAG, "Это моё сообщение для записи в журнале");Пользователи не видят журнал логов. Вы, как разработчик, можете увидеть его через программу LogCat, доступный в Android Studio.
Напишем простой пример с кнопкой.
package ru.alexanderklimov.flamingo import android.os.Bundle import android.util.Log import android.widget.Button import androidx.appcompat.app.AppCompatActivity class MainActivity : AppCompatActivity() < private val TAG = this.javaClass.simpleName override fun onCreate(savedInstanceState: Bundle?) < super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val button: Button = findViewById(R.id.button) button.setOnClickListener < Log.i(TAG, "Кот нажал на кнопку") >> >Запускаем программу и в студии открываем вкладку Logcat:

Вы увидите несколько строк с технической информацией.
--------- beginning of system --------- beginning of main --------------- PROCESS STARTED (25918) for package ru.alexanderklimov.flamingo --------------- 2023-05-24 16:31:08.294 25918-25961 OpenGLRenderer .Если нажать на кнопку, то появится новая информация — наш приготовленный текст.
2023-05-24 16:51:57.482 25918-25918 MainActivity ru.alexanderklimov.flamingo I Кот нажал на кнопкуОбратите внимание, что по умолчанию в Logcat установлен фильтр package:mine . Это позволяет отсечь множество системных сообщений, которые вам не нужны. Вы можете удалить фильтр и увидеть все эти сообщения. Убедившись, что они вам действительно не нужны, верните фильтр обратно.
Фильтры можно настраивать по своему вкусу. Например, если у вас много категорий логов, то можете выбрать нужный. Просто начинайте вводить текст, подсказки будут вам помогать при вводе текста. Например, добавим ещё один фильтр.
package:mine level:infoДля нашего примера особо ничего не изменилось. Дело в том, что категория info включает в себя все остальные категории. Фильтр level:warn будет показывать только категории Warning и Error.
Кроме показа сообщений о своём приложении через фильтр package:mine можно установить фильтры для других приложений: package:package-ID (указать идентификатор)
Если вы установили много тэгов, то посмотреть только нужные можно через фильтр tag:. Тогда вы не увидите лишние записи, которые были по умолчанию.
package:mine tag:MainActivityМожно убрать лишние записи через знак минуса. Например, уберём тэг OpenGLRenderer:
package:mine -tag:OpenGLRendererВсе логи имеют временную метку. Можно использовать фильтр age с указанием интервала.
- age:30s — логи за последние 30 секунд
- age:2m — логи за последние 2 минуты
- age:1h — логи за последний час
- age:2d — логи за 2 дня
Кстати, все ваши фильтры запоминаются и хранятся в истории. Нажмите на значок слева от фильтра, чтобы увидеть полный список. У каждого фильтра есть крестик, позволяющий удалить фильтр из истории.

Слева в списке фильтров есть значок звёзды — вы можете поместить любимые фильтры в Избранное.
Есть и другие фильтры, а также возможность использовать регулярные выражения. Но на первых порах достаточно использовать базовые возможности.
В левой части Logcat есть различные значки. Один из них отвечает за внешний вид журнала логов: можно выбрать вариант Standard View или Compact View. Либо вы можете настроить под себя, выбрав Modify Views, тогда у вас откроется диалоговое окно с настройками.
Можно создавать несколько вкладок Logcat, нажимая на значок +.
Далее идёт текст к старой версии Logcat. Возможны некоторые разночтения с новой версией, но в целом всё работает.
Полный вид сообщения выглядит следующим образом.
03-09 20:44:14.460 3851-3879 / ru.alexanderklimov.cat I/OpenGLRenderer : Initialized EGL, version 1.4
- 03-09 20:44:14.460 Date/Time
- 3851-3879 Process & Thread IDs
- ru.alexanderklimov.cat Package name
- I/OpenGLRenderer Tag
- Initialized EGL, version 1.4 Message
Подобные длинные сообщения не всегда удобны для чтения. Вы можете убрать ненужные элементы. Для этого выберите значок LogCat Header в виде шестерёнки и уберите флажки у опций.

В LogCat вы можете отфильтровать сообщение по заданному типу, чтобы видеть на экране только свои сообщения. Для этого выберите нужный тип тега из выпадающего списка Verbose.
Типы сообщений можно раскрасить разными цветами через настройки File | Settings | Editor | Colors Scheme | Android Logcat.
Для отслеживания сообщений с заданным текстом введите в поле поиска нужную строку и нажмите Enter.
Также активно используйте варианты из других выпадающих списков. Например, выбирайте свой пакет из второй колонки, а в последней выбирайте Show only selected application. Для более точной настройки используйте Edit Fiter Configuration.

По умолчанию, окно LogCat выводится в нижней части студии. При желании, можно выбрать другие варианты через значок настроек окна.
LogCat также можно запустить из командной строки:
adb logcat
Параметры командной строки смотрите в документации.
Быстрое отключение журналирования
Настоятельно рекомендуется удалять все вызовы LogCat в готовых приложениях. Если проект очень большой и вызовы журналирования разбросаны по всем местам кода, то ручное удаление (или комментирование) становится утомительным занятием. Многие разработчики используют следующую хитрость — создают обёртку вокруг вызова методов LogCat.
public static final boolean isDebug = false; public final String TAG = "MyLogger"; public void MyLogger(String statement) < if (isDebug) < Log.v(TAG, statement); >>Теперь остаётся только присвоить нужное значение переменной isDebug перед созданием готового apk-файла для распространения.
Способ устарел. В 17-й версии Android Build Tools появился класс BuildConfig, содержащий статическое поле DEBUG. Можно проверить следующим образом:
if (BuildConfig.DEBUG) < // Режим отладки, ведём логи >Способ для продвинутых — например, требуется релиз с выводом в лог, или наоборот — debug с выключенным выводом. В этом случае можно создать собственный параметр и добавить его в секцию buildType gradle-файла:
buildTypes < release < // Здесь настройки релиза buildConfigField "boolean", "USE_LOG", "false" >debug < buildConfigField "boolean", "USE_LOG", "true" >// «Релиз с логами» наследуем от обычного релиза releaseWithLog.initWith(buildTypes.release) releaseWithLog < buildConfigField "boolean", "USE_LOG", "true" >>В этом случае конфигурация releaseWithLog будет являться релизной сборкой с ведением логов. Естественно, в коде слегка поменяется проверка:
if (BuildConfig.USE_LOG) < // Здесь используем логи >LogCat на устройстве
Попался в сети пример для просмотра сообщений LogCat на устройстве. С примером не разбирался, оставлю здесь на память.
Разметка для элемента списка:
Добавляем разрешение в манифест:
package ru.alexanderklimov.test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import android.app.AlertDialog; import android.app.ListActivity; import android.content.Context; import android.graphics.Color; import android.os.AsyncTask; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; public class TestActivity extends ListActivity < private LogStringadapter adapter = null; private ArrayListlogarray = null; private LogReaderTask logReaderTask = null; @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); logarray = new ArrayList(); adapter = new LogStringadapter(this, R.id.txtLogString, logarray); setListAdapter(adapter); logReaderTask = new LogReaderTask(); logReaderTask.execute(); > @Override protected void onDestroy() < logReaderTask.stopTask(); super.onDestroy(); >@Override protected void onListItemClick(ListView l, View v, int position, long id) < super.onListItemClick(l, v, position, id); final AlertDialog.Builder builder = new AlertDialog.Builder( TestActivity.this); String text = ((String) ((TextView) v).getText()); builder.setMessage(text); builder.show(); >private int getLogColor(String type) < int color = Color.BLUE; if (type.equals("D")) < color = Color.rgb(0, 0, 200); >else if (type.equals("W")) < color = Color.rgb(128, 0, 0); >else if (type.equals("E")) < color = Color.rgb(255, 0, 0); ; >else if (type.equals("I")) < color = Color.rgb(0, 128, 0); ; >return color; > private class LogStringadapter extends ArrayAdapter < private Listobjects = null; public LogStringadapter(Context context, int textviewid, List objects) < super(context, textviewid, objects); this.objects = objects; >@Override public int getCount() < return ((null != objects) ? objects.size() : 0); >@Override public long getItemId(int position) < return position; >@Override public String getItem(int position) < return ((null != objects) ? objects.get(position) : null); >public View getView(int position, View convertView, ViewGroup parent) < View view = convertView; if (null == view) < LayoutInflater vi = (LayoutInflater) TestActivity.this .getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = vi.inflate(R.layout.logitem, null); >String data = objects.get(position); if (null != data) < TextView textview = (TextView) view .findViewById(R.id.txtLogString); String type = data.substring(0, 1); String line = data.substring(2); textview.setText(line); textview.setTextColor(getLogColor(type)); >return view; > > private class LogReaderTask extends AsyncTask < private final String[] LOGCAT_CMD = new String[] < "logcat" >; private final int BUFFER_SIZE = 1024; private boolean isRunning = true; private Process logprocess = null; private BufferedReader reader = null; private String[] line = null; @Override protected Void doInBackground(Void. params) < try < logprocess = Runtime.getRuntime().exec(LOGCAT_CMD); >catch (IOException e) < e.printStackTrace(); isRunning = false; >try < reader = new BufferedReader(new InputStreamReader( logprocess.getInputStream()), BUFFER_SIZE); >catch (IllegalArgumentException e) < e.printStackTrace(); isRunning = false; >line = new String[1]; try < while (isRunning) < line[0] = reader.readLine(); publishProgress(line); >> catch (IOException e) < e.printStackTrace(); isRunning = false; >return null; > @Override protected void onCancelled() < super.onCancelled(); >@Override protected void onPreExecute() < super.onPreExecute(); >@Override protected void onPostExecute(Void result) < super.onPostExecute(result); >@Override protected void onProgressUpdate(String. values) < super.onProgressUpdate(values); adapter.add(values[0]); >public void stopTask() < isRunning = false; logprocess.destroy(); >> >