четверг, 16 октября 2008 г.

Знакомство с Android. Часть 1: Простое приложение для Android

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

UPDATE

Серия статей по игре Life обновлена 03.11.2010. Исправлены ошибки и проведена адаптация под Android версии 2.2. Всем спасибо за замечания и дополнения!

Постановка задачи

Первым нашим приложением для Android будет реализация всем известной игры Life. Местом дейтвия будет прямоугольное клеточное поле, размеры которого запрашиваются у пользователя. Также у пользователя запрашивается начальное количество клеток. Первое поколение расставляется по карте случайным образом. Последующие поколения получаются по следующим правилам:
  • Если у живой клетки меньше двух или больше трёх соседей, то она погибает.
  • Если у пустой клетки ровно три соседки, она оживает.
Все входные параметры должны проверяться на правильность: столбцов должно быть не меньше 5 и не больше 25, строк должно быть не меньше 5 и не больше 35, начальное количество клеток должно быть не больше, чем ячеек на поле. Для реализации поля будет использован класс GridView.
Для разработки была использована среда Eclipse и Android plugin для неё.
Статья будет из четырех частей:
Итак, начнём.

В этой части

Мы создадим проект, рассмотрим его структуру и напишем простое приложение, состоящее из одной формы. На форме будет интерфейс для ввода данных и кнопка Run.

Создание и обзор проекта

На установке Android SDK и плагина для Eclipse останавливаться не будем, т.к. это достаточно подробно описано в официальном мануале. Создаем в Eclipse новый Android Project:
Создание нового проекта под Android
После нажатия на кнопку Finish создастся новый проект с такой структурой файлов:
Структура проекта
Рассмотрим эту структуру внимательнее.

/res/drawable-dpi

Сюда помещаются все графические файлы, используемые в приложении, для разных разрешений экрана. На данный момент там есть только файл icon.png - главная иконка приложения.

/res/layout

В эту папку помещаются файлы, в которых в формате XML описывается внешний вид форм, расположение контролов и т.д. (как dfm-ки в Дельфи). Плагин даже создал разметку для нашей единственной формы и назвал её main.xml. Позже мы рассмотрим ее подробнее.

/res/values

В этой папке хранятся общие константы для всего приложения, как то: текст, используемый элементами управления, цвета, стили и т.д.. Например, если мы хотим вывести "Hello World" в TextView, можно это сделать явно в разметке, как мы всю жизнь делали в тех же dfm-ках или aspx; либо создать в strings.xml константу hello со значением "Hello World", после чего пойти обратно в разметку и в атрибутах этого TextView прописать android:text="@string/hello".

/gen/R.java

Это такой специальный сгенерированный класс, посредством которого осуществляется доступ к ресурсам приложения (т.е. ко всему тому, что есть в папке res). Например, R.string.hello возвращает константу с именем hello из strings.xml.

StartActivity.java

Это нам плагин сгенерировал класс для главной (и пока что единственной) формы приложения. Там пока содержится единственный обработчик onCreate, и написано там только setContentView(R.layout.main);. С помощью этой строчки к данной форме привязывается разметка, описанная в файле /res/layout/main.xml

AndroidManifest.xml

В этом файле перечисляются общие свойства проекта (версия, package и прочее), а также все формы (Activities), входящие в проект.

Разметка формы (Layout)

Элементы управления в Android называются Views и наследуются от класса View или ViewGroup. Класс ViewGroup также унаследован от View, но его отличие в том, что в него могут быть вложены другие View или ViewGroup.
Иерархия View
Плагин создал простейшую разметку для нашей единственной формы (main.xml):

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
</LinearLayout>
Вначале задаётся Layout, т.е. правило, согласно которому элементы управления следуют друг за другом. LinearLayout значит, что они идут друг за другом сверху вниз (android:orientation="vertical"). Бывают и другие Layout-ы: TableLayout, с помощью которого можно выстроить контролы в таблицу; FrameLayout, который ставит контролы один на другой; и т.д.
Мы воспользуемся TableLayout
Сделаем вот такую разметку:

main.xml

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:stretchColumns="1"
    android:padding="10dip"
    >
    <TableRow android:paddingBottom="5dip">
        <TextView
            android:text="@string/columns_title"
            android:paddingRight="10dip"
            android:gravity="right"
            android:textStyle="bold"
        />
        <EditText
            android:id="@+id/columns_count"
            android:text="25"
            android:inputType="number"
        />
    </TableRow>
    <TableRow android:paddingBottom="5dip">
        <TextView
            android:text="@string/rows_title"
            android:paddingRight="10dip"
            android:gravity="right"
            android:textStyle="bold"
        />
        <EditText
            android:id="@+id/rows_count"
            android:text="35"
            android:inputType="number"
        />
    </TableRow>
    <TableRow android:paddingBottom="5dip">
        <TextView
            android:text="@string/cells_title"
            android:paddingRight="10dip"
            android:gravity="right"
            android:textStyle="bold"
        />
        <EditText
            android:id="@+id/cells_count"
            android:text="100"
            android:inputType="number"
        />
    </TableRow>
    <TableRow>
        <Button
            android:id="@+id/run"
            android:text="@string/run_title"
            android:textStyle="bold"
            android:layout_span="2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
        />
    </TableRow>
</TableLayout>
В файл res/values/strings.xml при этом нужно добавить следующие строки:

strings.xml

<string name="run_title">Run!</string>
<string name="columns_title">Columns:</string>
<string name="rows_title">Rows:</string>
<string name="cells_title">Cells:</string>
Форма при этом будет выглядеть так:
StartActivity
Рассмотрим некоторые атрибуты, использованные в разметке

android:id

Идентификатор элемента. Если он указан, то в дальнейшем его можно найти на форме с помощью метода findViewById(id). Для контролов, которых мы не планируем в дальнейшем трогать (например, для заголовков), можно это свойство и вовсе не указывать. Идентификаторы можно складывать в файл ids.xml, но вместо этого обычно применяется синтаксис @+id/View1. Это означает, что идентификатор View1 добавляется в константы прямо на ходу. В R.java соответствующие поля также добавляются автоматически.

android:layout_width и android:layout_heigth

Свойства layout_width и layout_heigth обозначают, какую часть родительского контрола будет занимать данный элемент управления: всю (fill_parent или match_parent, начиная с 2.2) или ровно столько, сколько требуется (wrap_content). Можно также задавать численные значения.

android:inputType

Это атрибут EditText. С его помощью можно устанавливать формат вводимого значения. Есть ряд предопределенных форматов (date, phone, etc). Значение number значит, что в это поле можно вводить только целые положительные числа.

android:gravity, android:layout_gravity

Устанавливает выравнивание в данном элементе управления. Отличие в том, что gravity задает выравнивание дочерних контролов, а layout_gravity задает выравнивание самого контрола.

Заключение

Итак, мы создали проект для Android, рассмотрели его структуру, составили разметку для нашей единственной формы.
Исходники примера

33 комментария:

iZEN комментирует...

Интересно, как вы сделали расцветку кода XML для публикования на blogspot.com?

darja комментирует...

Я написала свой подсветчик синтаксиса, и он умеет раскрашивать код не только цветами (<span style="color=...">), но и классами (<span class="...">). Ну а соответствующие классы я добавила прямо в шаблон блога. Если Firebug-ом посмотреть на css-ку моего блога, можно легко их там увидеть.

Анонимный комментирует...

Спасибо огромное.
Я тоже заинтересовался этой платформной. Правдя я только начинающий программист :)

Вообще-то я тестер. И вот, что я Вам скажу:

Здесь немного перепутаны значения полей: ColumnsEditor для Rows.

Просто так будет легче остальным пробовать начинать :)))
То же самое в папочке res в проекте Life для скачивания.
Еще раз Огромное спасибо :)
http://iamandroid.ru/ - линка с которой я узнал о Вас :)

4i4a

darja комментирует...

Ой, и вправду. Спасибо за замечания, исправила.

truf комментирует...

небольшая неточность:

Статья будет из трёх частей:

* Часть 1
* Часть 2
* Часть 3
* Часть 4

Анонимный комментирует...

Отличная статья. Пытаюсь освоить новую платформу. Но хочу заметить, что программировать интерфейс пользователя на Visual Studio для Windows Mobile гораздо легче.

Mike комментирует...

Спасибо за мануал. Очень заинтересовала платформа, начинаю ковырять. И вот не могу понять в чем проблема: в main.xml все теги закрыты и соответствуют друг другу, но выползает ошибка - "Element type "TableLayout" must be followed by either attribute specifications, ">" or "/>"."(Eclipse + Android SDK)

Yulik комментирует...

У меня та же самая фигня. Долго ковырялся, пытался понять, в чем проблема. В итоге просто перебил текст вручную. Все запахало :)

женя комментирует...

все проблема в символах перевода строк(пробелы. хз). Тупо копируем и вручную все заново переводим на новые строки..

BOJIKOJIAK комментирует...

Подскажите - а есть ли среды разработки, полностью работающие на телефоне под управлением андроида? :) Аппарат так и просит, чтобы вся работа делалась непосредственно на нём :)

darja комментирует...

2 BOJIKOJIAK
Хотите прямо на телефоне софт писать? Однако сурово. Сильно сомневаюсь, что такое бывает.

Анонимный комментирует...

Не знаю как на андроиде, а вот для простого мобильника первые приложения делал на самом мобильнике :)

darja комментирует...

2 Анонимный №3:
Неужели IDE на телефоне запускали? И через T9 код писали?

Дмитрий комментирует...

По поводу разработки непосредственно на девайсе - существует Android Scripting Environment (ASE) - позволяет писать скрипты на Lua, Perl'e, Python'e, Tcl'e. Так же реализована поддержка shell (BeanShell) и есть подержка jRuby.

Анонимный комментирует...

Darja, u vas v razmetke stranicy "sledushee" i "predydushee" naoborot)

Анонимный комментирует...

делаю всё как написано, а он выдает ошибку Element type "TableLayout" must be followed by either attribute specifications, ">" or "/>" и error: Error parsing XML: not well-formed (invalid token).
При этом указывает на строчку android:layout_width="fill_parent".
помогите пожалуйста разобраться.

volkodav комментирует...

наткнулся на интересную бету DroidDraw. Умеет пока немного, но все же проще, да и мопнятне ифейс рисовать в ней, чем руками в xml

Анонимный комментирует...

Ссылки перехода следующее и предыдущие перепутаны. )) Блог замечательный.)

Анонимный комментирует...

Начал пробовать свои силы в android 2.2. Так вот атрибут "android:numeric" считается там устаревшим и рекомендуется использовать android:inputType

ЗЫ: блог замечательный, написано аккуратно, по полочкам. Спасибо за Ваши труды.

darja комментирует...

Ваша правда, спасибо, исправилась.

Black Diver комментирует...

Кстати IDE уже не предлагает в автоподстановке android:layout_span
но предлагает android:layout_weight, который дает тот-же самый эффект.

Vladimir комментирует...

Добрый день!

Возможно где-то писалось, но не нашел.

Как устанавливается свойство, чтобы при изменении ориентации телефона ориентация приложения не менялась?

Vladimir комментирует...

Спасибо, нашел и разобрался.

http://www.goodroid.ru/faq/programming-for-android-os/disable-screen-orientation-change.html

Анонимный комментирует...

http://russia-android.ucoz.ru/load январская книжка 2011 г. по теме.

Анонимный комментирует...

скопировал ваш код, получил ошибку:
error: Invalid start tag TableLayout
в файлt main.xml

Анонимный комментирует...

Здравстуйте, Дарья!
Недавно видел пару Ваши статей на androidfan.ru

Анонимный комментирует...

Black Diver комментирует...
Кстати IDE уже не предлагает в автоподстановке android:layout_span
но предлагает android:layout_weight, который дает тот-же самый эффект.


Свойство android:layout_weight работает аналогично свойству weigth из класса библиотеки Swing (Java SE): GridBagConstraints.

Legalaid комментирует...

Отличный пост!

Александр комментирует...

Спасибо за пост. Все доступно и понятно.

sergey комментирует...

Мне кажется на Windows xp легче программировать чем для android

Oleg комментирует...
Этот комментарий был удален автором.
Oleg комментирует...

Пытаюсь освоить Android. Пишу программу для отправки СМС. Вопрос: как прочитать данные из активного окна при приеме СМС?
Т.Е. имеем активное окно в котором набираем номер телефона и текст и нажимаем кнопку отправить. Далее перехватываем ответную СМС. Событие перехвата написано в другом классе. В нем надо принять СМС и сравнить с номером телефона при отправке. Далее текст принимаемой СМС вывести в EditText активного окна.

AVL комментирует...

"Элементы управления в Android называются Views и наследуются от класса View или ViewGroup. Класс ViewGroup также унаследован от View, но его отличие в том, что в него могут быть вложены другие View или ViewGroup."
Этой фразой вы взорвали мой императивный мозг...