Журнал LinuxFormat - перейти на главную

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:

LXF129 81 1.jpg Эмулятор 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() обеспечивает требуемую реакцию на выбранный пользователем пункт меню. Он у нас всего один, так что здесь не заблудишься!

Наконец, нам нужен метод, создающий новый элемент (то есть добавляющий его в базу данных):

LXF129 82 1.jpg Вот DDMS в действии. Проверьте серые области!

 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 с собственными коллективами разработчиков.

Персональные инструменты
купить
подписаться
Яндекс.Метрика