Ресурсы
Ресурсом в Android является файл (музыкальный файл) или строка (название диалогового окна), которая связана с исполняемым приложением. Их можно изменять без перекомпиляции приложения.
Ресурсы включают в себя строки, цвета и растровые изображения. Вместо жёсткого кодирования строк в приложении, можно использовать их идентификаторы. Такой подход позволяет изменить текст строки ресурса без изменения исходного кода.
Строки как ресурсы
Строки как ресурсы представляют собой определение одной или нескольких строк в XML-файле(ах). Эти XML-файлы находятся в директории values (/res/values). Их названия задаются произвольно. Однако наиболее часто используемым является "strings.xml". Ниже приведён пример такого файла.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">hello</string>
<string name="app_name">hello appname</string>
</resources>
Когда данный файл создаётся или обновляется, Eclipse ADT плагин автоматически создаёт или же обновляет файл R.java, который можно найти в поддиректориях директории "gen". Данный файл содержит уникальные идентификаторы всех ресурсов приложения и существует в единственном экземпляре. Вышеопределённые строки в R.java будут выглядеть следующим образом:
package com.mycompany.android.my-root-package;
public final class R {
// ... другие записи в зависимости от вашего проекта и приложения
public static final class string
{
// ... другие записи в зависимости от вашего проекта и приложения
public static final int hello=0x7f040000;
public static final int app_name=0x7f040001;
// ... другие записи в зависимости от вашего проекта и приложения
}
// ... другие записи в зависимости от вашего проекта и приложения
}
Чтобы обратиться к строке из кода, необходимо использовать её идентификатор (например, R.string.hello). Данная конструкция выглядит следующим образом:
String hello = getString(R.string.hello);
Layout-ресурсы
При программировании под Android внешний вид приложения часто загружается из XML-файла. Эти XML-файлы называниются макетами (layouts). Они являются ключевыми при программировании Android UI (User Interface - пользовательский интерфейс).
Пример использования layout-ресурса:
public class HelloWorldActivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tv = (TextView)this.findViewById(R.id.text1);
tv.setText("Try this text instead");
}
...
}
В данном примере внешний вид HelloWorldActivity устанавливается с помощью функции "setContentView()" из файла "main.xml", который находится в папке "layout" .
Пример файла "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:id="@+id/text1"
<TextView android:id="@+id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button android:id="@+id/b1"
<Button android:id="@+id/b1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@+string/hello"
/>
/>
</LinearLayout>
Главным элементом в нём является LinearLayout. Это так называемый корневой узел, который содержит в себе ряд элементов активити (в нашем случае - одно поле с текстом (TextView) и одку кнопку (Button)). Он имеет набор атрибутов. Например, атрибут android:orientation="vertical" указывает на то, что все элементы, входящие в данный LinearLayout, будут располагаться вертикально (оно также может принимать значение "horizontal").
Для каждого активити приложения необходимо создавать отдельный макет (XML-файл).
Вернёмся немного назад. Как вы, наверное, уже заметили, такие ресурсы как поля с текстом, кнопки, объявляются в XML-файле. К ним можно "достучаться" из кода при помощи функции findViewById и их идентификатора. Идентификатор задаётся в XML-файле следующим образом:
<TextView android:id="@+id/text1"
...
/>
Значение атрибута android:id указывает на то, что для идентификации данного TextView будет использоваться значение "text1". Знак плюс (+) в "@+id/text1" означает, что данный идентификатор будет создан в том случае, если его ещё не существует.
Синтаксис ссылок на ресурсы
При создании ссылок на ресурсы необходимо придерживаться определённого синтаксиса. Так синтаксис атрибута id в примере @+id/text1 имеет следующую структуру:
@[пакет:] тип / имя
пакет - соответствует пакету в котором находятся исходные ресурсы с файлом R.java;
тип - соответствет одному из типов, доступных в R.java:
1. R.drawable
2. R.id
3. R.layout
4. R.string
5. R.attr
1. R.drawable
2. R.id
3. R.layout
4. R.string
5. R.attr
В XML-файле данные типы указываются как:
1. drawable
2. id
3. layuot
4. string
5. attr
1. drawable
2. id
3. layuot
4. string
5. attr
имя - имя данное ресурсу программистом.
Если при создании ссылки не указывать пакет, то будет использоваться текущий.
Чтобы лучше понять синтаксис ресурсов приведём несколько примеров ниже:
<TextView android:id="text">
// Ошибка компиляции, id не может быть обычной текстовой строкой
<TextView android:id="@text">
// неправильный синтаксис, пропущено имя типа
// вы получите ошибку "No Resource type specified"
<TextView android:id="@id/text">
// Ошибка: Не обнаружен ресурс с id равным "text"
// В том случае, если ранее не был объявлен ресурс с id равным "text"
<TextView android:id="@android:id/text">
// Ошибка: Ресурс не является общим
// Это говорит о том, что нет такого ресурса в android.R.id
<TextView android:id="@+id/text">
// Успех: Создан id с названием "text" в текущем пакете в файле R.java.
Компилируемые и некомпилируемые Android-ресурсы
Большинство ресурсов, используемых при Android-программироании, компилируются в бинарные файлы, при компиляции самого приложения. Однако некоторые из них остаются "как есть".
Ресурсы в Android представляются 2 типами файлов: XML-файлы и raw-файлы (изображения, аудио, видео). XML-файлы могут быть файлами строк (используемых в качетсве ресурсов) либо layout-ресурсов, которые имеют стандартный формат, а также файлами с произвольной структурой. Если вы хотите, чтобы XML-файлы с произвольной структурой компилировались в бинарные файлы, их необходимо поместить в директорию /res/xml. Если же их разместить в директории /res/raw, то при компиляции они будут включены в приложение в явном виде (это оносится и к другим файлам, находящимся в данной директории).
Список некоторых важных поддиректорий директории /res и типы ресурсов, которые они содержат:
- anim: компилируемые файлы анимации;
- drawable: растровые изображения;
- layouts: файлы, определяющие внешний вид UI;
- values: массивы, цвета, размеры, строки и стили;
- xml: компилируемые произвольные XML-файлы;
- raw: некомпилируемые raw-файлы.
Цвета как ресурсы
Для того, чтобы локализовать цвета, их определяют в файлах ресурсов (подобно строкам). Это позволяет применять различные "темы" для одного приложения.
Обратиться к идентификатору какого-либо цвета можно через "R.color.имя_ресурса". В Android также имеется базовый набор цветов. К ним можно обратиться через android.R.color.имя_ресурса (имена данных ресурсов доступны по адресу http://code.google.com/android/reference/android/R.color.html).
Пример файла ресурсов с определёнными в нём цветами выглядит следующим образом:
<resources>
<color name="red">#f00</color>
<color name="blue">#0000ff</color>
<color name="green">#f0f0</color>
<color name="main_back_ground_color">#ffffff00</color>
</resources>
Данный файл должен располагаться в /res/values директории. Его имя задаётся произвольным образом.
Использовать цвет из файла ресурсов в коде можно следующим образом:
int mainBackGroundColor = activity.getResources.getColor(R.color.main_back_ground_color);
Также его можно использовать при создании layouts:
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="@color/ red"
android:text="Sample Text to Show Red Color"
/>
/>
Подробнее о строках как ресурсах
При создании ресурсов из строк существуют некоторые ньюансы. Строки могут быть представлены обычными строками, строками с одинарной кавычкой, строками с двойными кавычками, "ява-строками" (строки java-формата), html-строками. Пример следует ниже:
<resources>
<string name="simple_string">простая строка</string>
<string name="quoted_string">"строка с ' кавычкой"</string>
<string name="double_quoted_string">\"двойные кавычки\"</string>
<string name="java_format_string">
Привет %2$s ява-строка. %1$s снова
</string>
<string name="tagged_string">
Привет <b><i>курсивный Android</i></b>, ты жирный.
</string>
</resources>
Использовать данные строки в коде можно следующим образом:
// Считывание обычной строки и установка её в TextView
String simpleString = activity.getString(R.string.simple_string);
textView.setText(simpleString);
// Считывание строки с кавычкой и установка её в TextView
String quotedString = activity.getString(R.string.quoted_string);
textView.setText(quotedString);
// Считывание строки с двойными кавычками и установка её в TextView
String doubleQuotedString = activity.getString(R.string.double_quoted_string);
textView.setText(doubleQuotedString);
// Считывание "ява-строки"
String javaFormatString = activity.getString(R.string.java_format_string);
// Подстановка аргуметов в строку
String substitutedString = String.format(javaFormatString, "Hello" , "Android");
// Установка преобразованной строки в TextView
textView.setText(substitutedString);
// Считывание html-строки из ресурсов
String htmlTaggedString = activity.getString(R.string.tagged_string);
// Преобразование исходной строки в обычную строку с учётом тегов
// android.text.Html класс позволяет отображать html-строки,
// однако он не поддерживает всех html-тегов
Spanned textSpan = android.text.Html.fromHtml(htmlTaggedString);
// Установка преобразованной строки в TextView
textView.setText(textSpan);
Единицы измерения как ресурсы
В Android основными единицами измерения являются пиксели (px), независимые от плотности пиксели (dp) и независимые от масштабирования пиксели (sp). Они также могут выступать в роли ресурсов. Например:
<resources>
<dimen name="mysize_in_pixels">1px</dimen>
<dimen name="mysize_in_dp">5dp</dimen>
<dimen name="medium_size">100sp</dimen>
</resources>
Список всех доступных в Android единиц измерения:
- px: пиксели;
- in: дюймы;
- mm: миллиметры;
- pt: точки;
- dp: независимые от плотности пиксели; абстрактная единицы измерения, основанная на физической плотности экрана;
- sp: независимые от масштабирования пиксели (используются, как правило, при установке шрифтов, т.к. наиболее корректно отображают их).
Изображения как ресурсы
Android автоматически создаёт идентификаторы для всех графических файлов, помещённых в директорию /res/drawable. Поддерживаются изображения с расширениями "gif", "jpg" и "png". Уникальный идентификатор генерируется из имени файла, поэтому при размещении двух файлов с одинаковыми именами в данной директории, будет выдана соответствующая ошибка. Также следует отметить, что компилятором игнорируются все поддиректории данной директории.
Использовать изображение из директории /res/drawable можно следующим образом:
BitmapDrawable d = activity.getResources().getDrawable(R.drawable.sample_image);
// Можно использовать объект изображения для установки фона кнопки
button.setBackgroundDrawable(d);
// либо сам идентификатор изображения
button.setBackgroundResource(R.drawable.icon);
Работа с произвольными XML-файлами
Как упоминалось выше произвольные XML-файлы также выступают в роли Android-ресурсов. Они, как правило, размещаются в директории /res/xml. Это даёт возможность обратиться к ним через автоматически созданный идентификатор. Пример произвольного XML-файла:
<rootelem1>
<subelem1>
Привет Миру из xml суб-элемента
</subelem1>
</rootelem1>
Чтобы распарсить (разобрать по элементам) данный XML-файл, необходимо использовать XMLPullParser. Пример парсинга приведён ниже:
private String getEventsFromAnXMLFile(Activity activity) throws XmlPullParserException, IOException
{
StringBuffer sb = new StringBuffer();
Resources res = activity.getResources();
XmlResourceParser xpp = res.getXml(R.xml.test);
xpp.next();
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT)
{
if(eventType == XmlPullParser.START_DOCUMENT)
{
sb.append("******Start document");
}
else if(eventType == XmlPullParser.START_TAG)
{
sb.append("\nStart tag " + xpp.getName());
}
else if(eventType == XmlPullParser.END_TAG)
{
sb.append("\nEnd tag " + xpp.getName());
}
else if(eventType == XmlPullParser.TEXT)
{
sb.append("\nText " + xpp.getText());
}
eventType = xpp.next();
} //eof-while
sb.append("\n******End document");
return sb.toString();
} //eof-function
Работа с raw-ресурсами
Android позволяет использовать произвольные ресурсы, такие как аудио, видео, текстовые файлы, расположенные в директории /res/raw. Эти файлы не компилируются при сборке приложения. Каждый из них имеет автоматически созданный идентификатор в файле R.java.
Пример использования raw-ресурса, можно рассмотреть на примере чтения файла test.txt, расположенного в каталоге /res/raw:
String getStringFromRawFile(Activity activity)
{
Resources r = activity.getResources();
InputStream is = r.openRawResource(R.raw.test);
String myText = convertStreamToString(is);
is.close();
return myText;
}
String convertStreamToString(InputStream is)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = is.read();
while (i != -1)
{
baos.write(i);
i = baos.read();
}
return baos.toString();
}
Работа с Assets
Assets представляет собой директорию, в которой можно хранить произвольные файлы. Она находится на одном уровне с директорией /res.
В отличии от /res, директория /assets позволяет создавать в ней произвольное количество подкаталогов. Для файлов, помещённых в данную директорию, не создаются идентификаторы. Чтобы обратиться к ним, необходимо указать относительный путь, начиная с /assets. Для доступа к этим файлам используется класс AssetManager:
String getStringFromAssetFile(Activity activity)
{
AssetManager am = activity.getAssets();
InputStream is = am.open("test.txt");
String s = convertStreamToString(is);
is.close();
return s;
}
Very good and detailed article.
ОтветитьУдалитьThanks to the author.
Спасибо за комментарий! :-)
ОтветитьУдалитьочень подробно, спасибо!
ОтветитьУдалитьделал динамическую кнопку(active+pressed+focuse) с созданием Layout-ута в проге, убился получать программно Drawable
строчка -
BitmapDrawable d = activity.getResources().getDrawable(R.drawable.sample_image);
практически спасла :)
надеюсь не сильно опоздал с комментом.
Sullen,
ОтветитьУдалитьЯ рад, что был полезен Вам :) Спасибо за комментарий.
Увы, у меня сейчас совсем нет времени вести свой блог. Надеюсь, я к нему еще вернусь.