Как работает сопоставление между ресурсами Android и идентификатором ресурсов?
Для Android просто волшебно найти нужный ресурс только через R.id.XXX.
AFAIK, ресурсы скомпилированы в двоичный формат, так как же эта логика отображения работает под капотом?
Может быть, это работает так:
Например, в layout1.xml мы получили:
<Button android:id="@+id/button1" >
и AAPT сгенерирует это в R.java:
public static final int button1=0x7f05000b;
Когда *.apk генерируется, @+id/button1 заменяется на "0x7f05000b".
Таким образом, когда мы называем:
findViewById(R.id.button1);
По сути, мы по-прежнему делаем поиск на основе идентификатора, хотя идентификатор представляет собой число, подобное 0x7f05000b.
Спасибо!
ДОБАВЛЯТЬ
Что я действительно хочу знать, так это то, как целое число идентификатора ресурса анализируется в содержимом ресурса? Другими словами, как среда выполнения Android находит контент ресурса с идентификатором ресурса в качестве единственной подсказки?
Например, как найти нарисованную картинку с идентификатором ресурса? Или как найти строковое значение с идентификатором ресурса?
5 ответов
Во время сборки инструмент aapt собирает все ресурсы, которые вы определили (за исключением отдельных файлов или явных определений в файлах), и присваивает им идентификаторы ресурсов.
Идентификатор ресурса представляет собой 32-разрядное число в форме: PPTTNNNN. PP - пакет, для которого предназначен ресурс; TT - тип ресурса; NNNN - это имя ресурса этого типа. Для ресурсов приложений PP всегда равен 0x7f.
Значения TT и NNNN назначаются aapt произвольно - в основном для каждого нового типа назначается и используется следующий доступный номер (начиная с 1); аналогично для каждого нового имени в типе присваивается и используется следующий доступный номер (начиная с 1).
Итак, если у нас есть эти файлы ресурсов, обрабатываемые aapt в следующем порядке:
layout/main.xml
drawable/icon.xml
layout/listitem.xml
Первый тип, который мы видим, - это "макет", поэтому ему присваивается TT == 1. Первое имя этого типа - "главный", поэтому ему присваивается NNNN == 1. Конечный идентификатор ресурса - 0x7f010001.
Далее мы видим "drawable", так что ему присваивается TT == 2. Первым именем для этого типа является "icon", так что получается NNNN == 1. Конечный идентификатор ресурса - 0x7f020001.
Наконец, мы видим еще один "макет", который имеет TT == 1, как и раньше. У него есть новое имя "listitem", так что он получает следующее значение NNNN == 2. Конечный идентификатор ресурса - 0x7f010002.
Обратите внимание, что по умолчанию aapt не пытается сохранить одинаковые идентификаторы между сборками. Каждый раз, когда ресурсы меняются, все они могут получить новые идентификаторы. Каждый раз, когда они создаются, создается новая R.java с текущими идентификаторами, поэтому ваш код получает правильные значения. Из-за этого вы никогда не должны сохранять идентификаторы ресурсов там, где они могут использоваться в разных сборках вашего приложения.
После того как ресурсы скомпилированы и присвоены идентификаторы, aapt создает файл R.java для вашего исходного кода и двоичный файл с именем "resources.arsc", который содержит все имена ресурсов, идентификаторы и значения (для ресурсов, которые поступают из отдельного файла их значением является путь к этому файлу в.apk) в формате, который можно легко отобразить и проанализировать на устройстве во время выполнения.
Вы можете получить сводную информацию о файле resources.arsc в apk с помощью команды "aapt dump resources
Формат таблицы двоичных ресурсов задокументирован в заголовочном файле для структур данных ресурса здесь:
Полная реализация для чтения таблицы ресурсов на устройстве:
https://github.com/android/platform_frameworks_base/blob/master/libs/androidfw/ResourceTypes.cpp
Если вы заинтересованы во внутренней реализации (на стороне устройства), взгляните на loadDrawable() в Resources.java. Обратитесь к отличному ответу hackbod для получения информации о извлечении данных из таблицы ресурсов.
Чтобы узнать, как макеты переводятся в View из ID ресурса, ознакомьтесь с LayoutInfater.java
Насколько я понимаю, aapt автоматически сгенерирует уникальные идентификаторы для каждого из ваших ресурсов и сохранит их в справочной таблице. Эта справочная таблица сохраняется в виде файла "resources.arsc", расположенного в "bin/resources.ap_" (это всего лишь файл ZIP, поэтому не стесняйтесь открывать его с помощью своей любимой программы просмотра ZIP). Справочная таблица также сохраняется как R.java, которая, как вы знаете, позволяет ссылаться на ваши ресурсы в Java.
Если вам нужна дополнительная информация о файле ARSC, я бы предложил поискать его в Google или просмотреть код http://code.google.com/p/android-apktool/.
Дан
Последнее замечание: долгое время я не использовал относительные макеты, потому что многие элементы должны ссылаться на элементы далее в файле XML, и я не знал, как ссылаться на @id/foo, который не был определен еще.
<!-- doesn't work -->
<TextView android:layout_above="@id/foo">above</textview>
<TextView android:id="@+id/foo">below</textview>
Затем однажды я понял (дух), что вы можете определить идентификатор в ссылке; это не должно быть в элементе, который несет идентификатор:
<!-- works -->
<TextView android:layout_above="@+id/foo">above</textview>
<TextView android:id="@id/foo">below</textview>
Магия заключается в плагине Eclipse и файле R.java, который он автоматически генерирует в папке "gen" приложения. Если вы загляните в этот файл, вы увидите статические отображения для каждого XXX в R.xx.XXX, где xx может быть anim, массивом, цветом и любым другим типом ресурса.