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

LXF130:Android

Материал из Linuxformat
Перейти к: навигация, поиск
Android Создаем приложения для открытой мобильной платформы

Содержание

Android: И так далее

Во второй части учебника по программированию для платформы Android Джульетта Кемп объяснит, как улучшить приложение и опубликовать его.

Месяц назад мы настроили среду разработки Android и написали основной код программы для составления списка. Сделаем программу немного более полезной, добавив возможность указать текст записи и создав пункт меню для удаления списка. Потом мы посмотрим, как поделиться этой программой с другими.


Важная особенность архитектуры Android – модульность приложений, и в одной программе можно использовать участки другой, если та это разрешает. А значит, незачем каждый раз разрабатывать собственные компоненты: гораздо эффективнее пустить в ход готовые. Поэтому в приложениях для Android нет единой точки входа – например, в отличие от других программ на Java здесь нет метода main(). Вместо этого программы строятся из компонентов. У вашей программы будет стартовая точка по умолчанию (указанная в файле AndroidManifest.xml), но она может выполняться и начиная с других точек, в зависимости от того, откуда вызвана. Структура программы – занятия, намерения и представления.

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

Занятия, Намерения и Представления

Существует четыре основных типа компонентов, но в этой программе используется только первый из них – Занятия:

  • Занятия (Activity) Каждое Занятие – визуальный интерфейс для определенного действия пользователя в приложении. У нас есть Занятие List – отображение списка элементов, и другое Занятие (мы создадим его сегодня), добавление элемента. Занятий может быть столько, сколько необходимо вашему приложению. У Занятия есть окно поумолчанию, полноэкранное либо всплывающее, а содержимое этого окна поставляется Представлениями. Каждое Представление управляет некоторым прямоугольником в окне и наследуется от базового класса View. Представления могут откликаться на действия пользователя в «подведомственной» области.
  • Сервисы (Service) У сервиса нет визуального интерфейса, но он работает в фоне (например, воспроизводит музыку). Обычно он продолжает работать после того, как пользователь покинул приложение.
  • Широковещательные приемники (Broadcast Receiver) Они принимают и реагируют на широковещательные оповещения, обычно от самой системы. В ответ на некоторые системные оповещения широковещательный приемник может выполнить действие.
  • Контент-провайдеры (Content Provider) Предоставляют данные приложения в доступ другим программам. Здесь нам это не понадобится, но наше приложение можно будет расширить, сделав его базу данных доступной другим приложениям.


Первые три типа компонентов активируются Намерениями [Intent], которые представляют собой объекты, содержащие сообщение. Сообщение может состоять из запроса действия и некоторых данных – мы воспользуемся ими позже на данном уроке.

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

registerForContextMenu(getListView());

Теперь создадим контекстное меню – точно так же, как создавали обычное. Добавьте следующий метод:


 public void onCreateContextMenu(Menu menu, View view,
 ContextMenuInfo info) {
 super.onCreateContextMenu(menu, view, info);
 menu.add(0, DELETE_ID, 0, R.string.menu_delete);
 }

DELETE_ID нужно определить в начале:

private static final int DELETE_ID = ADD_ID + 1;

Несмотря на то, что элементы добавляются в различные меню, вам понадобится использовать разные значения для двух констант, иначе элемент меню не отобразится должным образом. Вам также понадобится задать строку menu_delete в res/values/strings.xml. Как мы обсуждали на прошлом уроке, наборы строк и другие данные приложения лучше хранить в разделе resources, а не смешивать с кодом.

<string name=”menu_delete”>Delete item</string>

Теперь напишем метод, обрабатывающий события при выборе пункта меню. Создайте метод из файла snippet1.txt в каталоге Magazine/Android нашего DVD. Опять же, в выражении switch есть только одна ветвь. Обратите внимание на разницу имен этого метода и метода onMenuItemSelected(), который мы написали в предыдущей статье. Эти методы предоставляет Android: сразу после создания меню методы с такими именами будут автоматически использованы для обработки его пунктов. Больше ничего делать не нужно.

Так как это контекстное меню, оно автоматически связывается с определенным элементом списка. Метод получает информацию о выбранном элементе, вызывает обработчик базы данных для удаления записи и снова получает данные из базы, так что изменение немедленно отображается на экране. Наконец, нам потребуется метод удаления данных в базе в ListDbAdapter.java:

 public boolean deleteItem(long rowId) {
 return mDb.delete(DB_TABLE, DB_ROWID +=+
 rowId, null) > 0;
 }

Он использует переданный идентификатор строки rowId и удаляет указанный элемент. Данный идентификатор передается из метода onContextItemSelected(), в котором он извлекается из базы данных.

Если вы не используете Eclipse, придется вручную импортировать классы в начале файла List.java – см. код на DVD.

Добавляем элемент с заголовком

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

Для этого создадим еще одно Занятие – ‘ListAdd’. Это будет класс ListAdd, который будет жить в файле ListAdd.java. Как говорилось выше, Занятие – нечто выполняемое внутри приложения, и у него обычно есть собственные установки экрана, оно обрабатывает собственные Представления и т. д.

Прежде всего нам понадобится код, вызывающий ListAdd из главного Занятия List. Измените метод createItem() в List.java таким образом:

 private void createItem() {
  Intent i = new Intent(this, ListAdd.class);
  startActivityForResult(i, ITEM_ADD);
 }

Намерение — способ реализации обмена информацией между Занятиями. В него мы передаем текущий контекст [this] и имя класса, которому мы собираемся передать объект Intent. Затем мы вызываем класс методом startActivityForResult(), передавая ему полученный объект Намерения и код, которым он воспользуется для идентификации результата. Вам также потребуется установить его значение в начале файла – подойдет любое:

private static final int ITEM_ADD=0;

Вместо startActivityForResult() вы можете воспользоваться startActivity(), но его имя подсказывает, что startActivity() не возвращает ничего из Занятия, которое он запускает. Здесь это не подходит, так как мы хотим получить строку и обработать ее. В общем, метод startActivityForResult() более удобен.

Далее обработаем строку, возвращаемую из действия ListAdd. Добавьте метод onActivityResult() – он выглядит следующим образом:

 @Override protected void onActivityResult(int requestCode,
 int resultCode, Intent i) {
 super.onActivityResult(requestCode, resultCode, i);
 if (resultCode == RESULT_CANCELED) {
 return;
 }
 Bundle extras = i.getExtras();
 switch(requestCode) {
 case ITEM_ADD:
 String label = extras.getString(ListDbAdapter.DB_ITEM);
 mDb.createItem(label);
 getData();
 break;
 }
 }

Этот метод обрабатывает все результаты всех Занятий, которые вызывает List: поэтому мы и передаем код идентификации. Здесь у нас единственное доступное значение, но если бы вы захотели делать что-то еще, например, редактировать элементы списка, потребовалось бы больше.

Сперва проверим, была ли операция отменена – тогда делатьничего не нужно. Значение переменной RESULT_CANCELED устанавливается в главном классе Занятия Activity, так что это глобальное возвращаемое значение. В классе ListAdd мы свяжем этот результат с кнопкой Cancel [Отмена].

Если Занятие не было отменено, мы берем связку (Bundle), ассоциированную с возвращенным Намерением. Она используется для получения карты дополнительных данных (extras), которая хранится внутри Намерения (мы заполним ее в классе ListAdd позже) и связывает строки с другими типами данных: это нечто вроде хэша, который возвращает данные по ключу. Как видите, в секции ITEM_ADD оператора switch мы получаем значение label (имя элемента, который будет добавлен в список) из extras по ключу ListDbAdapter.DB_ITEM. Для ключа понадобится статическая переменная (вы будете обращаться к ней из нескольких классов), и неплохо использовать существующую и релевантную статическую строку. В данном случае, это столбец базы данных, где будут храниться данные. Затем вызывается метод обработчика базы данных, и метод getData() обновляет данные на экране.

Последнее, что нужно сделать – создать класс, который сделает всю работу. Взгляните на код класса ListAdd на нашем DVD, в нем всего один метод:


 @Override
 public void onCreate(Bundle savedInstanceState)
 {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.newitem);
 label = (EditText) findViewById(R.id.newitemlabel);
 Button okButton = (Button) findViewById(R.id.okbutton);
 cancelButton = (Button) findViewById(R.id.cancelbutton);
 okButton.setOnClickListener(new View.OnClickListener()
 {
 public void onClick(View view) {
  Bundle bundle = new Bundle();
 bundle.putString(ListDbAdapter.DB_ITEM,
 label.getText().toString());
 Intent i = new Intent();
 i.putExtras(bundle);
 setResult(RESULT_OK, i);
 finish();
 }
 });
 cancelButton.setOnClickListener(new View.
 OnClickListener() {
 public void onClick(View view) {
 Intent i = new Intent();
 setResult(RESULT_CANCELED, i);
 finish();
 }
 });
 }

Этот метод вызывается при активации Занятия из List (а вообще-то, и из любого другого Занятия). Устанавливается раскладка Представлений (см. файл newitem.xml на DVD – в нем есть блок EditText, куда можно ввести текст, и кнопка OK).

Мы получаем значение label (представляющее собой объект EditText, объявленный в начале класса) из раскладки по его идентификатору ID newitemlabel, а затем также получаем кнопку OK из раскладки как объект, снова идентифицируя его по ID. То же происходит и для кнопки Cancel.

Самая важная часть кода – метод setOnClickListener() для кнопки OK: он определяет, что произойдет по ее нажатию. Создается новая связка [Bundle], и к ней добавляется пара: ключ (строка DB_ITEM, используемая в коде обработки возврата в классе List) и значение из блока EditText, преобразованное в строку. Наконец, создается Намерение, принимающее связку; результат устанавливается в OK (RESULT_OK – стандартное значение, заданное в классе Activity), и Занятие завершается. Затем результат вернется в вызывающее Занятие (в нашем случае – List), которое обработает его в соответствии с уже написанным нами кодом.


Нам также понадобится метод setOnClickListener() для кнопки Cancel. Он проще: в нем лишь создается пустой объект Intent и используется глобальная константа RESULT_CANCELED, означающая, что действие было отменено. Последняя задача – добавить свой класс в файл AndroidManifest.xml, иначе он не будет найден во время компиляции. Добавьте строку

<activity android:name=”.ListAdd”></activity>

после тэга </activity>, завершающего листинг действия .List.

Скомпилируйте свой код (ant debug), запустите эмулятор, загрузите его и попробуйте! Для отладки кода воспользуйтесь ddms и проверьте файлы журналов, детали работы с которыми описаны в предыдущей статье.

Публикация приложения

Пока у вас получилась отладочная (debug) версия программы. Следующий шаг – сделать из нее окончательную (release) версию, которой можно будет поделиться с другими. Все приложения Android должны быть заверены сертификатом разработчика, который может быть самоподписанным. Также нужно задать переменные android.versionCode и android.versionName в разделе <manifest>.

Перед публикацией вам следует протестировать вашу программу на настоящем устройстве, если это вообще возможно. Не мешает также нарисовать иконку и указать ее в атрибуте android.icon секции <application> файла AndroidManifest.xml. Сам файл иконки сохраните в каталоге res/drawable.

Редактируя AndroidManifest.xml, нужно также указать в нем значение android.label, название вашей программы в меню приложений. Удалите из манифеста атрибут android:debuggable=«true» и убедитесь, что в коде программы не осталось отладочных команд.

Первый шаг – создание окончательной версии, пока не подписанной. Это сделает команда ant release (в отличие от ant debug). Далее создайте свой сертификат с помощью Keytool (проверьте, что ссылка из /usr/bin/keytool указывает на версию в JDK, а не gjc). Рекомендуется задать срок действия в 25 лет, чтобы гарантировать возможность будущих обновлений без проблем для пользователя (сертификаты будут проверяться во время установки/обновления). Если вы хотите разместить приложение на Android Market, вам придется указывать именно этот срок. Он соответствует 9130 дням, которые мы округлим до 10 000.

keytool -genkey -v -keystore ~/android/release-keys.keystore -alias listapp -keyalg RSA -validity 10000

У вас запросят пароль для keystore, кое-какую персональную информацию о вас и пароль для ключа. Используйте сложные пароли или парольные фразы. Для keystore можно указать любой путь.

Затем подпишите приложение с помощью Jarsigner, запустив эту команду в подкаталоге /bin/ директории вашей программы:
jarsigner -verbose -keystore ~/android/release-keys.keystore List-unsigned.apk listapp

Здесь listapp – псевдоним для ключа, List-unsigned.apk — само приложение, а -keystore задает ключевое хранилище – нужно указать полный путь к нему.

Итак, приложение подписано; дайте ему какое-нибудь значимое имя, используя mv List-unsigned.apk List.apk. Теперь можно проверить, что программа подписана, командой:

jarsigner -verify List.apk

Еще раз проверьте финальную версию, и затем ее можно публиковать. Самый простой способ сделать это – просто выложить файл .apk на ваш сайт: пользователи смогут загрузить его и установить приложение с помощью AppManager или похожей программы.

Альтернатива – воспользоваться Android Market (http://market.android.com/publish), который требует регистрации и взноса в 25 долларов, но упрощает загрузку приложения.

Будем надеяться, наши уроки дали вам общее понятие о написании программ для Android. В сети есть масса полезных ресурсов: очень хороша документация разработчика для Android, есть и форумы, где можно задать вопрос разработчикам. Чтобы упростить создание интерфейса, попробуйте DroidDraw (http://www.droiddraw.org) – созданный нами интерфейс довольно примитивен! Также можно взглянуть на расширение Google API: оно позволит связать вашу программу с Google Maps. Как мы уже говорили, архитектура Android позволяет вызывать части кода других программ: приложение со списком Намерений (Intents List Appendix) в документации разработчика Android содержит все программы Google, которые можно вызвать (например, браузер или программу для звонков по телефону), и сообщает как это сделать. Вытакже можете рассмотреть API для определения движения.

Дальнейшие шаги

Наши уроки вас заинтриговали? Не останавливайтесь на достигнутом: есть масса способов улучшить написанное нами приложение. Вот несколько из них для начала. Обратите внимание, что некоторые из них могут потребовать изменения – или полной переработки – кода для работы с базой данных.

  • Добавить возможность редактирования элемента: можно воспользоваться классом ListAdd и переданным объектом Intent для хранения информации о текущих значениях метки элемента и идентификатора строки в базе данных.
  • Добавить обработку ввода, чтобы, например, нажатие Enter обладало тем же эффектом, что и нажатие кнопки OK в окне «Добавить элемент».
  • Улучшить управление жизненным циклом, чтобы кнопка «Назад» работала правильно.
  • Добавить флажки рядом с каждым элементом.
  • Реализовать массовое удаление.
  • Добавить к элементу категорию, поле примечания или другие информационные поля.
  • Поищите сайты программ для составления списков и подумайте, не поучаствовать ли.
Персональные инструменты
купить
подписаться
Яндекс.Метрика