- Подписка на печатную версию:
- Подписка на электронную версию:
- Подшивки старых номеров журнала (печатные версии)
LXF129:Android
Материал из Linuxformat.
- Android Создаем приложения для открытой мобильной платформы
Содержание |
Android: ОС под роботы
Android |
---|
|
- Android – открытая платформа для смартфонов, и с ней легко создавать и публиковать программы, что Джульетта Кемп и продемонстрирует.
Телефон Nexus 1, с помпой представленный в январе этого года – лишь один из представителей славного семейства смартфонов, базирующихся на открытой платформе Android от Google. Android работает на ядре Linux, над которым расположен набор созданных в Google специальных Java-библиотек. Благодаря модели Open Source, для Nexus 1 или G1 легко начать разработку и выпуск собственных приложений, написанных на Java с использованием библиотек Android, наряду со стандартными библиотеками Java. Даже если у вас нет собственного Android-устройства, инструментарий разработчика, свободно доступный онлайн, включает эмулятор телефона для тестирования на нем программ. (Разумеется, рекомендуется проверить продукт на реальном телефоне, прежде чем выпустить его на волю.)
В данной серии статей я за два урока проведу вас через все шаги, связанные с настройкой среды разработки, написанием несложного приложения для создания списков и выставлением его на суд общественности. На сегодняшнем уроке мы рассмотрим разработку и тестирование, и получим первую версию приложения. Так что заправьтесь кофейком, установите телефон в беззвучный режим и приготовьтесь открыть для себя мир разработок Android – не так уж там страшно.
Часть 1 Настройка среды разработки
Для начала скачайте Android SDK. Подойти к разработке Android можно двумя способами: либо использовать Eclipse (среду для программирования на Java) с модулем расширения Android, что потребует от вас некоторых дополнительных усилий; или делать все вручную. На нашем уроке мы примем второй вариант, частично ради большего контроля над происходящим, а частично потому, что Eclipse слишком уж медлителен на старых машинах (включая мой настольный компьютер!).
Учтите, что для работы с последней версией Android потребуется версия Java 1.6: она доступна как opennjdk-6‑jdk для Debian/Ubuntu. Также потребуется запустить sudo update-alternatives --config java для корректной установки используемой версии Java.
Android SDK имеется на сайте разработчиков (http://develoPer.android.com/index.html). Скачайте, распакуйте и установите его куда хотите – например, в /usr/local/android-sdk-linux_x86/. Проверьте правильность прав пользователя и группы, и вам останется только отредактировать .bashrc или .bash_profile для включения каталога tools в $PATH:
export PATH=${PATH}:/usr/local/android-sdk-linux_x86/tools/
Откройте новое окно терминала (или наберите source .bashrc), чтобы изменения вступили в силу. Теперь необходимо добавить платформу. К сожалению, простого способа сделать это локально не предусмотрено, поэтому мы не можем предоставить вам все необходимое на LXFDVD. Введите команду android, перейдите в Available Packages и выберите из списка Andoid 1.5 – пакет будет скачан с серверов Google. Среда разработки готова к использованию. Мы настроим стенд для тестирования и эмулятор телефона потом: сначала создадим пустой проект, чтобы было куда поместить наш код для последующего редактирования. Создайте рабочий каталог и, перейдя (cd) в него, сгенерируйте новый проект при помощи инструмента android:
mkdir ~/android/ cd ~/android android create project --package com.example.list --activity List \ --target 1 --path ~/android/List
Опция --package определяет пространство имен для вашего нового пакета. Правила здесь те же, что и для пространств имен пакетов Java; основное – берется собственное имя домена (или вашей организации) и записывается покомпонентно в обратном порядке. То есть, example.com превращается в com.example.list (если домена у вас нет, как вариант можно использовать local.example.list, но тогда есть риск конфликтов в пространстве имен).
Аргумент --activity устанавливает имя вашего основного класса действий – Activity (более подробно о действиях мы поговорим через месяц, а сейчас просто запомните, что это имя главного класса в вашем проекте). --target – это набор библиотек, которые вы собираетесь использовать. 1 (в моей системе) – это Android 1.5: выполните android list targets, чтобы выяснить возможные варианты. --path – каталог проекта, который при необходимости будет создан.
Теперь наберите cd ~/android/List и взгляните на структуру директорий. Ваш код находится в src/com/example/list; другая важная папка – res/, там живут ресурсы пакета. AndroidManifest.xml – это манифест, содержащий информацию о приложении для среды Android. Здесь хранится структура компонентов приложения, приводятся необходимые библиотеки и определяется минимально необходимый уровень API (для более подробной информации, см. документацию разработчика). Еще один полезный файл – build.xml, инструкции для Ant, инструмента сборки. Вам, скорее всего, незачем прикладывать руку к этим двум файлам.
На данном этапе здесь нет кода, который что-то выполняет. Но android генерирует для вас заготовки классов, и их мы можем скомпилировать. В родительском каталоге, выполните:
ant debug
(при возникновении ошибок, установите пакет ant или apache-ant из репозиториев дистрибутива). Проверьте bin: там должен быть файл List-debug.apk. Вы можете установить его в эмуляторе для тестирования, но поскольку эмулятор у нас еще не настроен, мы этого делать не будем. Цель debug используется при разработке; через месяц мы посмотрим, что делать, если надо собрать программу для распространения.
Разработка с Eclipse
Для использования Eclipse нужно скачать SDK; запомните, куда вы его поместили, и измените ваш $PATH соответственно.
Вам понадобится как минимум версия Eclipse 3.3; ее можно найти на сайте Eclipse. Установив и запустив Eclipse, перейдите в Help > Install Software и наберите http://dl-ssl.google.com/eclipse/android в Work With (если возникнyт сложности, попробуйте http:// вместо https://).
Поставьте галочку рядом с Developer Tools для модуля расширения Android, затем выберите Install. В следующем окне укажите, что надо установить оба инструмента, DDMS и dev, затем нажмите Next, примите лицензионное соглашение и нажмите Finish.
Часть 2 List.java
Напишем несложное приложение для создания списков, в которые можно добавлять элементы, а также удалять их. В качестве хранилища применим простую базу данных. Прежде всего, создадим основной класс (файл List.java). Именно он будет выполняться при запуске приложения; и пока что он будет лишь показывать имеющийся список (то есть вытаскивать все существующие объекты из базы данных) и создавать пункт меню для добавления нового элемента.
List расширяет ListActivity – это класс Android, отображающий список элементов и управляющий различными обработчиками событий, которые генерируются, когда пользователь выбирает элемент или щелкает по нему. Activity, по сути, тот класс, который работает с «чем-то, что делает пользователь» в вашем приложении. (Приложение может иметь несколько Activity, но наше пока обойдется одним!)
В верхней части класса находится несколько закрытых переменных и объектов, которые понадобятся нам позже. Метод OnCreate вызывается, когда создается класс (т. е. когда запускается приложение):
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mDb = new ListDbAdapter(this); mDb.open(); getData(); registerForContextMenu(getListView()); }
Строка @Override (она называется «аннотацией») сообщает компилятору, что мы намерены перекрыть метод родительского класса. R.layout.main мы рассмотрим позже.
Остальные методы относятся к настройкам взаимодействия с базой данных, сбору информации из нее и регистрации контекстного меню (тип меню, которое появляется, когда вы делае те длительное нажатие, что в Android эквивалентно щелчку правой кнопкой мыши). Метод registerForContextMenu() унаследован от ListActivity.
Если у вас медленный компьютер, вам может показаться, что 1.5 версия тестовой среды изрядно тормозит. Установите 1.1 AVD с ис пользованием -t 1 и используйте его для начального тестирования.
Теперь напишем метод GetData(), получающий данные из базы:
private void getData() { private void getData() { mCursor = mDb.fetchAllItems(); startManagingCursor(mCursor); String[] cols = new String[] { ListDbAdapter.DB_ITEM }; int[] views = new int[]{ R.id.text1 }; SimpleCursorAdapter row_cursor = new SimpleCursorAdapter(this, R.layout.list_row, mCursor, cols, views); setListAdapter(row_cursor); }
mCursor – одно из определенных нами закрытых полей типа Cursor. Курсор позволяет получить доступ к объекту, возвращенному запросом к базе данных (то есть запрос к базе данных возвращает Cursor; методы для работы с базами данных мы рассмотрим далее, когда будем писать класс интерфейса к БД). startManagingCursor – еще один метод, унаследованный от ListActivity; через него Android осуществляет управление курсором.
Следующая строка создает String [], массив строк для наших столбцов – в данном случае столбец только один, DB_ITEM (опять же см. ниже). Строка за ней устанавливает массив int в соответствии с массивом String: каждая запись в массиве int определяет вид-представление (View), с которым связан соответствующий столбец в массиве String. Здесь, столбец DB_ITEM связан с представлением R.id.text1. (Подробнее о представлениях см. на втором уроке. Пока вкратце поясним, что они управляют областями экрана.) SimpleCursorAdapter создает раскладку по строкам (R.layout.list_row), и связывает массив cols с views. Наконец, setListAdapter ассоциирует все это с представлением списка.
Далее создадим три метода меню. Первый добавляет в него элементы:
public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(NONE, ADD_ID, NONE, R.string.menu_add); return true; }
У нас только один пункт меню: его метка опредена в R.string.menu_add (ее мы зададим чуть позже), а местоположение определяется ADD_ID (который был установлен в верху класса равным константе Menu.FIRST, так что этот пункт будет первым). Первый NONE означает, что данный пункт не должен входить в группу, а второй NONE означает, что нам не важен порядок.
Далее разберемся, что происходит, когда пользователь нажимает на пункт меню: мает на пункт меню:
public boolean onMenuItemSelected(int id, MenuItem item) { switch(item.getItemId()) { case ADD_ID: createItem(); return true; } return super.onMenuItemSelected(id,item);
Блок switch() обеспечивает требуемую реакцию на выбранный пользователем пункт меню. Он у нас всего один, так что здесь не заблудишься!
Наконец, нам нужен метод, создающий новый элемент (то есть добавляющий его в базу данных):
private void createItem() { /* позже нам надо будет реализовать способ передачи сюда реальных данных */ mDb.createItem(getString(R.string.new_item)); getData(); }
Более сложную часть обработки пользовательского ввода оставим на второй урок из этой серии; сейчас все, что нам нужно сделать – это добавить в базу данных запись, содержащую текст, который хранится в ресурсе R.string.new_item (см. ниже). Затем мы вновь считываем из базы все данные, что, в свою очередь, обновляет экран приложения, и вы видите только что созданный пункт.
Теперь давайте посмотрим на эти строки в R и вышеупомянутые раскладки.
Строки и прочее
Взглянув на свою директорию List, вы увидите подкаталог под названием res. Там хранятся все ресурсы приложения. Ресурсами в Android называются почти все элементы, внешние по отношению к коду, на которые вы можете сослаться: картинки, раскладки, строковые данные и прочее.
В рамках этого проекта у нас пока что есть только раскладка и пара строк. Раскладка хранится в res/layout/, а строковые данные – в res/values/strings.xml. Вам нужно отредактировать этот файл, чтобы он выглядел следующим образом:
<?xml version=”1.0” encoding=”utf-8”?> <resources> <string name=”app_name”>List</string> <string name=”menu_add”>Add item</string> <string name=”new_item”>New item</string> </resources>
Как видите, это XML-файл с достаточно простым форматом. Мы указали имя приложения и две строки, используемые в файле List.java. Они называются R.string.menu_add и R.string.new_item, и вы уже видели их в коде выше. Хранить все строковые константы в этом файле – хорошая практика: это более эффективно и упрощает жизнь, если надо что-то менять, а когда в Android настанет время поддержки интернационализации и локализации, ваше приложение будет в более выгодной позиции для внедрения всего этого.
Ресурсы возвращаются как Char-Sequence. Если вы уверены в том, что получите строку, используйте метод getString(), как показано в create Item(). Это нужно не всегда, но пригодится, если вы получите ошибку компиляции, связанную с ресурсами.
Другой род ресурсов, которым мы уже пользовались – раскладки (layout). Основная раскладка, в res/layout/main.xml, выглядит следующим образом:
<?xml version=”1.0” encoding=”utf-8”?> <LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android” android:layout_width=”wrap_content” android:layout_height=”wrap_content”> <ListView android:id=”@+id/android:list” android:layout_width=”wrap_content” android:layout_height=”wrap_content” /> <TextView android:id=”@+id/android.empty” android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:text=”No items in this list” /> </LinearLayout>
Вы можете заметить, что здесь указан конкретный текст. Лучше будет заменить строку с ним на другую:
android:text=”@string/empty_list”
@ обозначает ссылку на строковую переменную, а так как она находится внутри пакета, не нужно указывать ничего, кроме имени и того, что это строка. Теперь добавьте в res/values/strings.xml
<string name=”empty_list”>No items in this list</string>
и ваша строка правильно выведена в ресурсы! Другой файл, на ко торый мы ссылались в нашем коде – res/layout/list_row.xml:
<?xml version=”1.0” encoding=”utf-8”?> <TextView android:id=”@+id/text1” xmlns:android=”http:// schemas.android.com/apk/res/android” android:layout_width=”wrap_content” android:layout_height=”wrap_content” />
Поле text1 использовано в методе getData:
int[] fields = new int[]{ R.id.text1 };
чтобы связать представление (R.id.text1, создаваемое здесь как TextView с переносом текста по ширине и высоте) с конкретным столбцом. Итак, вот что мы сделали: для указанного столбца мы установили данное представление, но оно было определено в ресурсах приложения, а не в коде. Это немного похоже на вынос визуальных стилей HTML в таблицы CSS: так легче внести изменения в раскладку, если вам захочется придать виду вашего приложения индивидуальность.
Часть 3 База данных и тестирование
Согласно документации, для просмотра журналов нужно запустить logcat из DDMS, но на самом деле это просто открывает второе окно журналов (в котором нет весьма полезного цветовыделения) с той же информацией.
Код для базы данных помещен в класс ListDbAdapter. В его начале устанавливаются различные константы и закрытые объекты, в том числе строка, которая будет создавать базу данных с двумя полями: целочисленным ключом и текстовым примечанием
private static final String DB_CREATE = “create table list (_id integer primary key autoincrement, “ + “item text not null);”;
Мы также создали внутренний класс DatabaseHelper, унаследованный от android.database.sqlite.SQLiteOpenHelPer. Он обеспечит фактическое взаимодействие с базой данных, используя строку DB_CREATE. Существует метод и для обновления структуры базы.
При создании ListDbAdapter нам нужен только Context – класс, предоставляемый системой Android, который действует как интерфейс к информации о среде приложения. Мы также реализовали методы open и close, которые ведут себя соответственно: открывают и закрывают хранилище.
Еще один интересный метод – CreateItem:
public long createItem(String item) { ContentValues content = new ContentValues(); content.put(DB_ITEM, item); return mDb.insert(DB_TABLE, null, content); }
ContentValues – реализация хэширования: значение записи хранится с DB_ITEM в качестве ключа, а затем DatabaseHelper mDb использует значение хэша при взаимодействии с базой данных и добавляет содержимое. Также есть методы удаления и возврата всех элементов (fetchAllItems).
Ну вот, теперь настроим нашу тестовую среду. Первым делом нужно создать виртуальное устройство Android (Android Vitrual Device, AVD): это эмулятор телефона. Можно создать несколько AVD, описывающих различные установки телефонов, и сохранять их данные независимо. Все, что вы сохраните в AVD во времяработы эмулятора, не уничтожается в перерывах между запусками. Для простого тестового телефона с последней версией Android, используйте
android create avd -n my_avd_1.5 -t 1
Цель (-t 1) та же, что и при создании проекта. Начните тестирование для нее, а затем можете проверить на разных AVD, обладает ли ваша программа прямой и/или обратной совместимостью. Вас спросят, хотите ли вы установить какие-либо аппаратные опции; ответ no выберет настройки по умолчанию. AVD сохранится в ~/.android/аvd.
Затем запустите эмулятор:
emulator -avd my_avd_1.5
Наконец, установите вашу программу на устройстве (эмулятор должен работать):
adb install ~/android/List/bin/List-debug.apk
Запустив эту команду, нажмите на закладке в нижней части экрана телефона и прокручивайте появившееся меню, пока не найдете элемент List. Нажмите на него, и он должен заработать.
Если вы изменили код и хотите перекомпилировать его и переустановить, воспользуйтесь ключом -r в adb install:
adb install -r ~/android/List/bin/List-debug.apk
Приложение останется установленным, если вы закрыли эмулятор и запустили его снова с тем же AVD: вся существующая информация в процессе выключения запоминается как часть дан ных AVD.
Отладка
На этом этапе ваш код должен работать идеально, но, к сожалению, так бывает не всегда. Эмулятор Android особой информации не дает: придется запустить отладчик DDMS. Он позволит автоматически подключаться к эмулятору, и здесь предусмотрено окно журналов в нижней части экрана, которое можно использовать для проверки стеков вызова и исключений. Для вывода информации из вашего приложения в журнал, используйте следующий синтаксис:
import android.util.Log; private static final String TAG = “List”; Log.i(TAG, “List.getData() - about to talk to database”); Log.w(TAG, “List.getData() - oh dear, something has gone wrong”);
Используйте строку TAG как метку действия, которое вы хотите журналировать (здесь – List; вы также можете вести журнал от класса ListDbAdapter и выбрать в качестве тэга его). Используйте журнал Log.d для отладки, Log.i – для информации, Log.e – для ошибок и Log.w – для предупреждений.
Ресурсы
Основной ресурс – руководство для разработчиков и документация, поставляемая вместе с SDK Android. Там очень много полезной информации, а также примеров кода: мне они невероятно пригодились при изучении программирования для Android.
Есть также несколько списков Групп Google (начинающим – android-beginners, разработчикам – android-developers и обсуждения – android-discuss): проверьте их описания и убедитесь, что находитесь в подходящем для вашего вопроса форуме, прежде чем его задать.
Если вы пользуетесь IRC, проверьте канал #android на сервере irc.freenode.net. Существуют также различные форумы Android с собственными коллективами разработчиков.