Поиск по этому блогу

четверг, 21 июля 2011 г.

Pro Android 2 - Глава 3. Использование ресурсов, контент-провайдеров и намерений (начало: ресурсы)

Ресурсы

Ресурсом в 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"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello"
    />
    <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

В XML-файле данные типы указываются как:

    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 можно следующим образом:

// Получение изображения при помощи метода getDrawable()
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; 
}

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

  1. Very good and detailed article.
    Thanks to the author.

    ОтветитьУдалить
  2. Спасибо за комментарий! :-)

    ОтветитьУдалить
  3. очень подробно, спасибо!

    делал динамическую кнопку(active+pressed+focuse) с созданием Layout-ута в проге, убился получать программно Drawable
    строчка -
    BitmapDrawable d = activity.getResources().getDrawable(R.drawable.sample_image);
    практически спасла :)
    надеюсь не сильно опоздал с комментом.

    ОтветитьУдалить
  4. Sullen,

    Я рад, что был полезен Вам :) Спасибо за комментарий.

    Увы, у меня сейчас совсем нет времени вести свой блог. Надеюсь, я к нему еще вернусь.

    ОтветитьУдалить