- Подписка на печатную версию:
- Подписка на электронную версию:
- Подшивки старых номеров журнала (печатные версии)
LXF130:Android
Материал из Linuxformat.
- Android Создаем приложения для открытой мобильной платформы
Содержание |
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), которое обработает его в соответствии с уже написанным нами кодом.
Чтобы запустить эмулятор, наберите emulator -avd myavd. Для переустановки в эмулятор существующего пакета, наберите adb in-stall -r List/bin/List-debug.apk.
Нам также понадобится метод 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 в окне «Добавить элемент».
- Улучшить управление жизненным циклом, чтобы кнопка «Назад» работала правильно.
- Добавить флажки рядом с каждым элементом.
- Реализовать массовое удаление.
- Добавить к элементу категорию, поле примечания или другие информационные поля.
- Поищите сайты программ для составления списков и подумайте, не поучаствовать ли.