Pull to refresh

Разработка под Android в NetBeans IDE без плагинов. Часть 2

Reading time11 min
Views12K
Продолжаем начатый эксперимент, посвящённый настройке NetBeans IDE для программирования под Android. В прошлый раз нам удалось создать проект в NetBeans, настроить систему сборки, а также сделать автоматический запуск приложения. Кроме этого мы немного посмотрели на то, как система сборки построена изнутри. Во второй части статьи мы пойдём дальше и посмотрим, как в NetBeans можно осуществлять отладку, создавать библиотечные проекты, а также добавлять библиотеки к проектам и работать с модульными тестами.

Отладка


Интересно, что отладку в NetBeans можно делать двумя способами. Первый способ даже не потребует никакого колдовства в ant. Второй будет немного посложнее настроить, но в некоторых случаях он пригождается, да и больше похож на то, что есть в Eclipse.

Способ №1

Перед тем, как начинать что-то делать, нужно вспомнить об инструменте под названием monitor. Находится он в папке <Android-SDK>/tools. Как я писал в прошлой части статьи, она уже должна быть в PATH, так можно запускать прямо из командной строки или строки поиска в Windows, но никто, конечно, не мешает и создать ярлык. Те, кто работал в Eclipse, сразу узнают все панельки в этом инструменте. Самые важные — это logcat и Devices.

После того, как monitor открыт, нужно запустить приложение, если оно ещё не запущено, и посмотреть, через какой порт нужно подключаться к отладчику. Порт пишется напротив приложения. По умолчанию они имеют схему 860x. Можно также щёлкнуть одно из приложений, чтобы назначить ему порт 8700. После этого в NetBeans нужно подключиться к этому порту через команду Attach Debugger. Выбираем параметры Socket Attach, localhost, необходимый порт… И всё, дальше можно спокойно заниматься отладкой.

Присоединение отладчика

На кнопке в панели запоминаются недавно введённые конфигурации, так что в следующий раз даже не придётся ничего вводить.

Запомненные конфигурации

Отдельно обращаю внимание, что monitor вызывается не только для того, чтобы посмотреть на порты. Он также выступает посредником в соединении с виртуальной машиной, так что, если он не запущен, подключаться наугад к порту 8600, увы, не выйдет.

У этого способа отладки есть то преимущество, что можно подключаться и отключаться в любой момент. Это важно, потому что с подлкючённым отладчиком Dalvik VM начинает заметно тормозить. Иногда это бывает не критично, но не всегда, поэтому возможность дойти до определённой точки выполнения в программе без отладчика, бывает, вовсе и не лишнее.

Есть и ещё один инструмент, который помогает подключить отладчик именно в определённой точке. Можно, конечно, создать точку остановки по условию, но, как я уже говорил, с подключённым отладчиком всё работает очень не шустро. Поэтому можно в коде вставить вызов Debug.waitForDebugger(). Как только программа дойдёт до этого метода, она застопорится, и исполнение продолжится дальше только после подключения отладчика.

Но иногда нужно начать отладку в момент запуска программы. Можно воспользоваться этим же вызовом вышеупомянутого метода, а можно и настроить в NetBeans второй способ запуска отладки.

Способ №2

Второй способ будет действовать так же, как и в Eclipse: запускаем отладку, и запускается само приложение. После этого оно ждёт подключения отладчика, и только потом продолжает запуск. NetBeans нам поможет и здесь. Если попробовать выполнить отладку (CTRL+F5), NetBeans предложит сгенерировать ant-файл, который подскажет ему, как её нужно проводить в нашем проекте. Именно это нам и нужно. После этого в подпапке проекта nbproject заведётся файл ide-file-targets.xml, содержимое которого нужно заменить на следующее:

<?xml version="1.0" encoding="UTF-8"?>
<project basedir=".." name="KillerApp-IDE">
	<import file="../build.xml"/>

	<target name="-load-props">
		<property file="nbproject/debug.properties"/>
	</target>

	<target name="-check-props">
		<fail unless="jpda.host"/>
		<fail unless="jpda.address"/>
		<fail unless="jpda.transport"/>
	</target>

	<target name="-init" depends="-load-props, -check-props"/>

	<target name="-launch-monitor">
		<if>
			<condition>
				<not>
					<socket server="localhost" port="8700"/>
				</not>
			</condition>
			<then>
				<exec executable="${android.tools.dir}/monitor${bat}"/>
				<waitfor maxwait="20" maxwaitunit="second">
					<socket server="localhost" port="8700"/>
				</waitfor>
				<sleep seconds="2"/>
			</then>
		</if>
	</target>

	<target name="-launch-debug" depends="-find-main-activity">
		<exec executable="adb">
			<arg line="shell am start -D"/>
			<arg line="${project.app.launcharg}"/>
		</exec>
	</target>

	<target name="debug-nb" depends="-init, -launch-monitor, -launch-debug">
		<nbjpdaconnect
			address="${jpda.address}"
			host="${jpda.host}"
			name="${ant.project.name}"
			transport="${jpda.transport}"
		/>
	</target>
</project>

Файл начинается с загрузки свойств из файла debug.properties, который нужно кинуть в ту же папку со следующим содержимым:

jpda.host=localhost
jpda.address=8700
jpda.transport=dt_socket

Теперь можно поразбираться, что этот файл делает. Основное задание здесь — это debug-nb, которое NetBeans запускает, когда начинается отладка, и зависит оно от заданий -init, -launch-monitor и -launch-debug. В -init ничего особенно интересного нет, задание просто загружает и проверяет переменные из файла debug.properties. А вот -launch-monitor уже позанятнее: нам ведь необходимо запустить monitor, если он ещё не запущен, и это задание как раз и берёт задачу на себя. В ant есть хорошее задание, которое позволяет посмотреть, слушает ли программа на определённом порте или нет — socket. По этому признаку как раз можно определить, работает ли monitor или нет. Если нет, то нужно его запустить и подождать (задание wait-for). После запуска ещё стоит подождать секунды две для того, чтобы monitor начал принимать соединения (значение, возможно, придётся немного скорректировать в зависимости от конкретной конфигурации оборудования).

После этого можно запускать само приложение. В прошлой статье мы уже это проделывали из ant с помощью командной строки. Для этого используется команда adb shell am start -a android.intent.action.MAIN -n <пакет приложения>/<активность>. В этот раз разберём команду немного подробнее. adb shell — это команда, позволяющая работать напрямую с командной строкой внутри Android. am — это менеджер активностей, у которого есть довольно впечатляющий набор возможностей; о них можно почитать в официальной документации. Нам же нужна лишь команда start для запуска нужной активности, которую мы указываем после ключа -n, а ключ -a задаёт, как уже, наверное, стало понятно, намерение.

В файле custom_rules.xml уже есть задание, которое выдаёт нужные для запуска параметры: -find-main-activity. В этот раз нам нужно запустить приложение точно так же, как и в прошлый раз, но с ключом -D, чтобы после запуска приложение не сразу продолжало работу, а сначала подождало отладчик.

Таким образом, после выполнения всех этих махинаций к запуску debug-nb уже всё готово: работает monitor, приложение запущено и ждёт отладчик. Осталось только его подключить с помощью задания nbjpdaconnect. Как понятно из названия, это задание сугубо специфическое для NetBeans.

Я сам пользуюсь вторым способом намного реже, чем первым, за счёт того, что, как я уже сказал, при подключении отладчика Dalvik VM начинает изображать тугодума, поэтому добраться до отлаживаемого участка в приложении становится дольше. Но, если проблема происходит при запуске приложения, этот способ — как раз то, что нужно.

Добавление библиотек и создание библиотечных проектов


Библиотека может быть прекомпилированным jar-файлом, а может быть и отдельным проектом Android, который нужно компилировать перед включением в проект. Подключаются они, соответственно, разными способами.

В случае прекомпилированного файла шагов очень мало:

  1. Нужно бросить файл в папку libs основной папки проекта.
  2. В свойствах проекта на вкладке Java Sources Classpath необходимо добавить путь к файлу. На самом деле, можно этого и не делать, но тогда IDE нам не будет подсказывать по коду из этой библиотеки, что сводит на нет преимущества использования IDE.

В случае библиотечного проекта всё немного похитрее. Можно его добавлять командой (и это официальный способ), а можно добавлять строчкой в конфигурационном файле. Для тех, кто любит официальный способ, нужна следующая команда:

android update project -p <путь к проекту> -l <путь к библиотеке относительно проекта>


Попробуем добавить ради примера библиотеку поддержки v7 appcompat, которую Google сделали для тех, кто хочет видеть панель действий на версиях Android до 3.0. Она как раз распространяется не как прекомпилированный jar-файл, а как библиотечный проект, поскольку там есть дополнительные ресурсы. Допустим, что он лежит в той же папке, что и наш основной проект.

android update project -p KillerApp -l ../AndroidCompatibilityPackage-v7-appcompat


Всё! Можно уже компилировать проект. Если мы заглянем в файл project.properties, то обнаружим в этом конфигурационном файле строчку

android.library.reference.1=../AndroidCompatibilityPackage-v7-appcompat


Собственно, это всё, что та команда и сделала. Точно таким же способом можно добавлять новые библиотеки безо всякой команды, главное только не забывать увеличивать номер библиотеки на единичку: android.library.reference.2, android.library.reference.3 и так далее.

Разумеется, как и с прекомпилированным файлом, нужно не забыть добавить на владке Java Sources Classpath упоминаемые в проекте папки исходников библиотечного проекта, а также библиотеки, которые использует он (если мы их также используем). То есть стоит добавить папки src, gen и jar-файлы в папке libs библиотечного проекта.

Что если мы хотим создать свой такой же проект? Создание библиотечного проекта происходит в точности так же, как и создание обычного проекта с тем исключением, что нужна немного другая команда:

android create lib-project -n <имя проекта> -t android-<уровень API> -p <путь к проекту> -k <пакет программы>


Основное отличие в том, что вводится lib-project вместо project. Кроме того, не нужно указывать название главной активности, поскольку библиотеку не придётся запускать напрямую. Дальше создание проекта продолжается так же, как и для обычного проекта.

Создание проектов для тестов


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

android create test-project -p <путь к проекту> -n <название проекта> -m <путь к основному проекту относительно проекта для тестов>


Проекты для тестов обычно создаются в подпапке основного проекта, поэтому создадим такой проект из папки основного проекта:

android create test-project -p tests -n KillerAppTest -m ..


Дальше можно продолжить создание нового проекта в NetBeans точно так же, как и в случае обычного проекта. Но на этот раз мы сможем оставить на третьем шаге пункт test, когда мы назначаем задания ant разным пунктам меню. А вот из Run Project теперь стоит убрать launch и оставить только debug install, поскольку запускать нам тут всё равно нечего.

Команды тестового проекта

Для обычного проекта после этого мы ещё добавляли файлы, связанные с запуском приложения, но в этот раз это нам ни к чему. А вот что можно сделать, так это добавить файлы, которые нам помогут отлаживать тесты и запускать их выборочно.

Для начала нужно сгенерировать файл для дополнительных заданий в NetBeans. Нам интересен запуск отдельных файлов, отладка и отладка отдельных файлов. Все эти действия можно сгенерировать нажатиями на CTRL+F6, CTRL+F5 и CTRL+SHIFT+F5. После этого в папку nbproject нужно опять закинуть файлы, как и при добавлении отладки в обычный проект по второму способу, только файл ide-file-targets.xml будет немного другой. Начало файла такое же, как и в случае отладки обычного проекта, поэтому весь файл целиком я не копирую. Желающие могут посмотреть его на BitBucket. А вот дальше у нас другие задания:

<target depends="-setup" name="run-selected-file-in-src">
	<fail unless="run.class">Must set property 'run.class'</fail>
	<echo level="info">Running tests in ${run.class}...</echo>
	<run-tests-helper>
		<extra-instrument-args>
			<arg value="-e"/>
			<arg value="class"/>
			<arg value="${run.class}"/>
		</extra-instrument-args>
	</run-tests-helper>
</target>

<macrodef name="launch-debug-and-connect">
	<element name="debugged-class" optional="yes"/>
	<sequential>
		<parallel>
			<run-tests-helper>
				<extra-instrument-args>
					<debugged-class/>
					<arg value="-e"/>
					<arg value="debug"/>
					<arg value="true"/>
				</extra-instrument-args>
			</run-tests-helper>
			<sequential>
				<sleep seconds="5"/>
				<nbjpdaconnect
					address="${jpda.address}"
					host="${jpda.host}"
					name="${ant.project.name}"
					transport="${jpda.transport}"
				/>
			</sequential>
		</parallel>
	</sequential>
</macrodef>

<target depends="-setup, -init, -launch-monitor" name="debug-selected-file-in-src">
	<fail unless="debug.class">Must set property 'debug.class'</fail>
	<echo level="info">Debugging tests in ${debug.class}...</echo>
	<launch-debug-and-connect>
		<debugged-class>
			<arg value="-e"/>
			<arg value="class"/>
			<arg value="${debug.class}"/>
		</debugged-class>
	</launch-debug-and-connect>
</target>

<target depends="-setup, -init, -launch-monitor" name="debug-nb">
	<launch-debug-and-connect/>
</target>

Задание run-selected-file-in-src нужно для запуска отдельных тестов. Оно использует макрос run-tests-helper, который определён в системе сборки Android с дополнительными параметрами. На самом деле, всё, что делает этот макрос — это запускает команду adb shell am instrument с параметрами для тестирования программы (да, это опять менеджер активностей). Мы добавляем к запуску команды аргументы -e class <тестируемый класс>, так что аппарат не будет гонять все тесты без разбора, а сосредоточится на конкретном файле.

Дальше остались задания, в которых нам нужно выполнить отладку. Для того, чтобы её сделать, нужно запустить сначала тестирование с указанием подождать отладчик, а потом подключиться. Но тут есть маленькая загвоздка: запуск тестирования происходит с блокировкой, а нам нужно запускать другое задание. Нас спасёт задание parallel, которое запускает разные задания вместе. Результат оформлен как макро, чтобы можно было регулировать, с какими параметрами вызывается тестирование. Соответственно, наши задания для отладки просто его вызывают, с дополнительными параметрами, если нужно.

Итог


Теперь можно подвести итоги тому, что мы натворили. Суммарно получился очень неплохой объём возможностей:

  • Полноценная сборка и запуск проектов;
  • Генерация R.java вручную;
  • Запуск отладки проектов;
  • Добавление библиотек и библиотечных проектов;
  • Создание проектов для тестирования;
  • Запуск отдельных тестов с возможностью отладки;
  • Подсказки и автозаполнение.

Проекты создаются одной командой из командной строки и парой дополнительных файлов, которые универсальны для каждого проекта, так что всё довольно просто по трудозатратам. Что у нас отсутствует по сравнению с тем, что уже есть в Eclipse или Android Studio:

  • Редактирование интерфейса;
  • Редактирование XML-файлов с подсказками;
  • Переход к объявлению ресурса.

Редактирование XML-файлов — это не так критично, но, разумеется, без WYSIWYG-редактора довольно грустно редактировать интерфейс. Поэтому я лично импортирую проект в Eclipse и редактирую интерфейс там, когда это требуется.

Ещё хочется сказать пару слов насчёт применимости подобных инструментов. В комменатриях к предыдущей статье подобные вопросы возникали, поэтому ещё раз напомню: это эксперимент. Если существует официальная система сборки через ant, независимая от IDE, то для меня было сложно удержаться и не попробовать с её помощью настроить инструмент, который изначально вовсе не был предназначен для работы с Android.

Кроме того, на самом деле, ведь необязательно пользоваться NetBeans, чтобы задействовать эту систему. После настройки проекта можно просто набирать в командной строке, например, ant debug install launch, чтобы собрать и запустить проект. И, в отличие от сборки самодельным скриптом, это будет полноценная сборка — в точности такая же, которую делает и Eclipse с ADT: с генерацией интерфейсов из AIDL, BuildConfig, RenderScript, zipalign, ProGuard и всем прочим. Что касается использования её для того, чтобы программировать в NetBeans, это уже, конечно, сильно на любителя. Но, в любом случае, мне лично было очень интересно провести этот эксперимент и надеюсь, что другим было интересно о нём прочитать.

Пара ссылок


  1. Все файлы на BitBucket
  2. Разработка под Android в NetBeans IDE без плагинов. Часть 1
Tags:
Hubs:
+11
Comments0

Articles

Change theme settings