Это древний текст, он уже неактуален и вряд ли кому понадобится, но пусть хранится для истории.
Java-классы проекта, макеты интерфейсов, ресурсы, доступ к ресурсам из кода
Сегодня займёмся редактированием кода проекта. В самом начале я заявил, что знание Java необязательно, однако это не значит, что я тут буду заниматься обучением этому языку, вам придётся самим что-то по этой теме читать; книг и обучающих ресурсов предостаточно, какие-то из них можно найти в ссылках в конце этой статьи.
Запускаем eclipse командой eclipse-adt
, там должен уже быть проект, который мы создали в прошлой части — first project, также запускаем эмулятор с виртуальным девайсом с Android 2.3.3.
Замечание Я позволю себе не вдаваться в детальные подробности, как именно открывать файлы в редакторе Eclipse, в прошлой части я рассказывал про вьюшки и в частности про Package explorer, также можно открывать файлы через диалог поиска eclipse-ресурсов, по умолчанию он висит на хоткее
Ctrl+Shift+R
, в нём вы можете просто набрать часть имени нужного файла, а потом стрелочками выбрать подходящий из списка, очень удобно.
Java-код¶
Итак, открываем в редакторе единственный пока java-файл нашего проекта — FirstprojectActivity.java
, он был автоматически сгенерён при создании проекта и выглядит примерно так:
package com.example.firstProject;
import android.app.Activity;
import android.os.Bundle;
public class FirstprojectActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Рассмотрим этот файл построчно.
package com.example.firstProject;
В этой строчке мы видим объявление пакета (package), пакет — это сгруппированный набор объектов, в названии пакета используется схема с точками, каждый элемент названия (т.е. между точками) соответствует каталогу в проекте. В нашем случае файл FirstprojectActivity.java
находится в каталоге (относительно каталога src
) com/example/firstProject
, все файлы (и классы в них) внутри этого же каталога также будут находиться в пакете com.example.firstProject
.
Вы, наверное, заметили, что название пакета напоминает доменное имя, записанное в обратном порядке. Так вот это именно так и есть! Такой способ является в Java общепринятым способом именования пакетов и библиотек, чтобы каждый использовал свой собственный DNS-домен как идентификатор своих пакетов и не пересекался с другими.
import android.app.Activity;
import android.os.Bundle;
В этом блоке мы импортируем
классы из других пакетов, теперь на них можно ссылаться в этом файле по короткому имени, в нашем случае это: Activity
и Bundle
.
public class FirstprojectActivity extends Activity {
Это обычное наследование, мы наследуем класс FirstprojectActivity
от класса Activity
из пакета android.app
.
@Override
public void onCreate(Bundle savedInstanceState) {
Здесь мы определяем метод onCreate
, по его названию можно догадаться, что он вызывается при создании чего-то. Ключевое слово @Override
говорит компилятору, что мы собираемся переопределять метод из родительского класса, если такого метода в родительском классе нет, мы получим ошибку в редакторе и компиляторе.
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Тут тоже всё просто: сначала вызываем этот метод из родительского класса, а затем — метод setContentView
с параметром R.layout.main
. Но где же начинается наша программа, если во всём проекте всего один класс с произвольным именем и странным методом?
Операции¶
Вам, возможно, знакома фраза «точка входа в программу», так обычно называет фрагмент кода, с которого начинается выполнение программы. Точкой входа может быть функция (например, функция main()
в C/C++), класс (например, в Java-программах). Однако у андроидных приложений НЕТ точки входа в таком понимании. Андроидное приложение (если рассматривать APK-пакет как одно цельное приложение) по сути является коллекцией компонентов-микроприложений, а какое из них будет «запущено», определяется контекстом.
Всего существует несколько типов таких компонентов, один из них вы уже увидели: наш класс com.example.firstProject.FirstprojectActivity
(а это его полное имя, вместе с содержащим его пакетом) является операцией (по-английски activity), так как отнаследован от класса android.app.Activity
. Именно в операции реализуется пользовательский интерфейс, грубо говоря, каждому «окну» приложения соответсвует одна операция. Когда система создаёт пользовательский интерфейс, она сначала конструирует объект на основе соответствующего класса операции, а затем вызывает метод onCreate()
, где приложение должно сформировать элементы интерфейса, запустить сетевые запросы, короче, инициализировать «окно». Приложение обязано в своём манифесте (файле AndroidManifest.xml
) определить все свои операции, это делается в секции <activity>
; если вы сейчас заглянете в манифесте нашего приложения, то увидите там примерно такое:
<activity
android:name=".FirstprojectActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Для каждой операции создаётся отдельный элемент <activity>
. По его внешнему виду примерно понятно, что там за атрибуты и какие у них значения. В android:name
находится название класса, в котором операция реализована (точка в начале имени означает, что имя относительное, т.е. должно находиться внутри главного пакета приложения, имя которого задано в атрибуте package
элемента <manifest>
). В android:label
находится человекочитаемое название операции, которое показывается пользователю; в нашем примере вы видите внутри значение @string/app_name
, это означает, что непосредтсвенное значение лейбла берётся из строковых ресурсов приложения, о них чуть ниже.
Внутри элемента <activity>
находится элемент <intent-filter>
, он определяет условия-интенты, при которых операция будет вызвана.
Интенты¶
Интент является ключевым элементом всей андроидной платформы, это слово очевидным образом произошло от английского intent, что в переводе значит «цель» или «намерение». Интент является запросом, который посылает приложение (или какой-нибудь другой компонент системы) с целью выполнить какое-нибудь действие. Например, если вы тыкаете по ссылке на веб-страницу внутри твиттер-клиента, приложение посылает запрос-интент в систему «Мне нужно открыть URL http://example.com». Система принимает этот запрос и дальше смотрит, заявило ли какое-нибудь приложение готовность принимать URL, если такое приложение нашлось, то ему перенаправляется запрос. Если у вас в системе несколько веб-браузеров, вы наверняка видели такую менюшку со списком браузеров — все они объявили, что принимают запросы на открытие веб-страниц.
Когда приложение или система посылают интент, они указывают действие (по-английски action, например, если хотят открыть веб-страницу в браузере, android.content.Intent.ACTION_VIEW
) и (опционально) данные (по-английски data, например, URL веб-страницы http://google.com
). Другой пример действия для интента, это — android.intent.action.MAIN
, оно обозначает нечто вроде действия по умолчанию, аналог точки входа в операцию и обычно вызывается, когда вы тыкаете по иконке приложения на экране.
Приложение объявляет о своей готовности принимать интенты в манифесте, в элементе <intent-filter>
, в нём должен содержаться обязательный элемент <action>
, где указывается строка с действием, в нашем примере это строка android.intent.action.MAIN
. Также в элементе <intent-filter>
может находиться элемент <category>
(в нём определяется категория интент-фильтра, например, чтобы в общем списке приложений появилась иконка, нужно указать категорию android.intent.category.LAUNCHER
, а если этого не сделать, то своё приложение вы банально на телефоне не найдёте) и data
(здесь указывается тип Uri, на которые будет реагировать этот фильтр).
Существует стандартный набор действий для интентов, предназначенный для базовых телефонно-планшетных операций, например, действие для запуска приложения-телефона — android.intent.action.DIAL
.
Представление¶
Представление (по-английски view) — это такой своеобразный «кирпичик», из которых состоит пользовательский интерфейс приложения. Представление с точки зрения программы является классом, наследником класса android.view.View
. Примеры стандартных представлений: Button, CheckBox, EditText и прочие интерфейсные элементы управления.
Любой интерфейс состоит из представлений, однако в нашей программе никаких классов представлений нет, да и в единственном классе не особо заметно какого-либо кода по созданию, например, надписи, которая на экране девайса показывается. Всё дело в том, что представления можно описывать декларативно и хранить в виде ресурсов.
Ресурсы¶
Ресурсы приложения предназначены для отделения всяких визуальных хреновин (картинок, представлений и даже текстовых строк) от кода программы. В ресурсах хранятся, например, элементы оформления приложения для разных размеров и разрешений экрана; там же хранятся текстовые строки для разных языков интерфейса.
В дереве проекта в eclipse все ресурсы хранятся в папке res
на верхнем уровне проекта (рядом с папкой src
). Если вы развернёте все подпапки в res
, то увидите примерно такое:
В папках drawable-hdpi
, drawable-ldpi
, drawable-mdpi
хранятся картинки для разных разрешений экрана. В папке layout
хранятся макеты интерфейсов, а в папке values
пока лежит только файл strings.xml
, в котором хранятся, в частности, все интерфейсные строки.
Давайте для начала откроем файл strings.xml
и посмотрим, что там внутри (сразу же переключимся на XML-вид, смотрите на табы в низу редактора):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, FirstprojectActivity!</string>
<string name="app_name">First project</string>
</resources>
Строки, определяемые в этом файле, автоматически становятся доступны по всему приложению, их даже можно использовать внутри манифеста (вспомните определение операции, там в атрибуте android:label
стояла ссылка на строку в виде @string/app_name
). Такой файл можно создавать для каждого поддерживаемого человеческого языка, при этом ссылки на эти строки будут автоматически конвертироваться в нужный язык, очень удобно.
Давайте поменяем строку с именем hello
на что-нибудь другое, например, так:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">And yet it moves!</string>
<string name="app_name">First project</string>
</resources>
Сохраним файл и запустим проект на выполнение, на экране виртуального девайса увидим вот такое:
Общее представление о строках получили, теперь о макетах интерфейсов. Эти самые макеты (по-английски layouts) представляют собой декларативное описание элементов интерфейса. Это очень удобно, так как не нужно вручную конструировать представления, выставлять им параметры, вместо этого рисуем в визуальном редакторе интерфейс и создаём его одним вызовом:
setContentView(R.layout.main);
Обратите внимание на конструкцию R.layout.main
, это одна из замечательных фич андроида: все ресурсы проекта после компиляции становятся доступны как элементы базового класса R. А в Eclipse ADT они же доступны прямо в процессе написания кода, сразу же после создания. В данном случае макет интерфейса был преобразован в объект класса View
и в таком виде стал доступен во время исполнения. ADT контролирует доступность ресурсов, то есть вы не сможете использовать ресурс, который ещё не создан — в редакторе это место будет помечено ошибкой.
Откроем файл res/layout/main.xml
в редакторе, видим уже привычный вид: в центральной области графическое представление редактируемого файла, внизу строка с двумя табами — Graphical Layout
и main.xml
, где мы можем переключаться между графическим видом макета и его XML-кодом.
Редактор интерфейсов самый обычный: слева набор доступных интерфейсных элементов, в середине макет, куда эти элементы можно таскать мышкой, этой же мышкой можно менять расположение элементов. Обратите внимание на надпись на макете — And yet it moves! — она автоматически подгрузилась из строковых ресурсов в уже изменённом виде.
Вы можете смело натаскать элементов с левой панели на макет и запустить проект, чтобы посмотреть, как они будут выглядеть на готовом приложении.
И под конец этой главы давайте поиграемся с локализациями: добавим поддержку русского языка. Для этого создадим в папке res
новую папку с названием values-ru
, для этого кликните правой кнопкой мыши по папке res
и выберите в меню New → Folder, в поле Folder name введите values-ru
и нажмите кнопку Finish. Теперь скопируйте в эту папку файл strings.xml
из папки res/values
(это можно сделать через контекстное меню: клик правой кнопкой мыши по res/values/strings.xml
, Copy, клик правой кнопкой по res/values-ru
, Paste). Откройте файл res/values-ru/strings.xml
в редакторе и наберите там что-нибудь по-русски, например, так:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">И всё-таки она вертится!</string>
<string name="app_name">Первый проект</string>
</resources>
Сохраните файл и запустите проект, в виртуальном девайсе должно открыться приложение, в нём все надписи на английском. Теперь переключитесь внутри девайса на русский язык (если забыли, это делается так: кнопка Home, кнопка Menu, Settings → Language and keyboard → Select language → Русский) и снова запустите приложение из Eclipse. Ура! Должно получиться так:
Ссылки¶
- Обучающий курс по Java от IBM
- Intent and Intent filters на официально девелоперском сайте андроида
Спасибо. У вас очень хороший стиль и все понятно. Пишите дальше.
Чувак Чувак, пиши еще! Всё понятно и это главное!
Хех (( жаль что нет продолжения.
Все супер...
подскажите как для кнопки создать открытие ссылки в установленном браузере