Скомпилированные ресурсы Android - resources.arsc
Я пытаюсь выяснить, что значит "компилировать ресурсы".
Что я сделал, чтобы понять эту проблему:
Я прочитал много статей на эту тему, но не нашел простого ответа. Лучшее, что я прочитал, было: Как работает сопоставление ресурсов Android и идентификатора ресурсов? ,
Как я это понимаю
Насколько я понимаю, когда мы компилируем наш проект с помощью ANT (Eclipse) или Gradle (AS). Мы используем инструмент под названием aapt - Android Asset Packaging Tool, который: используется для генерации уникальных идентификаторов для каждого из наших ресурсов, таких как макеты, стили и т.д., И для сохранения их в справочной таблице. Затем он сохраняет эту таблицу поиска, генерируя два файла:
- Он генерирует файл R.java с этими уникальными идентификаторами, чтобы мы могли использовать наши ресурсы из нашего кода Java во время компиляции.
- Он генерирует файл resources.arsc, который можно найти в файле resources *.ap_. Этот файл resources.arsc будет позже упакован с помощью apktool в apk.
Этот формат файла arsc - это формат, который будет легко отображаться и анализироваться устройством во время выполнения.
Пример:
Итак, чтобы сделать это просто: допустим, у меня есть это в моем activity_main.xml:
<TextView android:id="@+id/my_textView"
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
И я звоню из моего onCreate, используя:
findViewById(R.id.my_textView)
В моем файле R.java я увижу:
public static final int my_textView=0x7f08003f;
Использование: aapt dump ресурсов на сгенерированном apk. Я вижу, что он содержит две строки с my_textView: ec resource 0x7f08003f com.example.lizi.liortest2: id/my_textView: flags = 0x00000000 resource 0x7f08003f com.example.lizi.liortest2: id/my_textView: t = 0x12 d = 0x00000000 (s = 0x0008 r = 0x00)
Что я не понимаю
Я бы подумал, что этот файл resources.arsc будет содержать не только идентификатор ресурса, но и все свойства, которые я определил для представления, например, android: layout_width = "wrap_content".
Так что теперь во время выполнения, когда виртуальная машина пытается запустить findViewById(R.id.my_textView)
Как он узнает, какое представление получить/свои свойства создать?
Я просто не могу понять, как это работает... Разве эта таблица поиска не должна содержать также данные свойств? И что это за номер 0x7f08003f? (Должно ли оно представлять значение, которое впоследствии будет сопоставлено с физической памятью, в которой будет храниться объект?)
Ответы
Ответ 1
TL; DR: с помощью компилятора Android (aapt) узлы xml будут переведены в классы Java и соответствующие атрибуты в числовые идентификаторы. Среда выполнения Android работает с этими идентификаторами для создания экземпляров классов с целью создания представлений.
TL, R
Запустите эту команду, чтобы сбросить двоичный XML
aapt d xmltree apk_file_name res/layout/activity_main.xml
(aapt можно найти в android-sdk-dir/build-tools/23.0.2/aapt.exe)
Это покажет узлы xml (например, LinearLayout
, RelativeLayout
и т.д.) С их атрибутами (например, android:layout_width, android:layout_height
) и их значения. Обратите внимание, что там можно match_parent
константы match_parent
(числовое значение 0xffffffff
или -1
) или wrap_content
(числовое значение 0xfffffffe
или -2
).
Фактически, вы можете использовать эту команду для любых других XML файлов в apk, например, AndroidManifest.xml or layout files
Файл apk - это просто zip-архив, содержащий все файлы классов java (classes.dex
), все скомпилированные файлы ресурсов и файл с именем resources.arsc
. Этот файл resource.arsc
содержит всю мета-информацию о ресурсах, узлах xml (например, LinearLayout
, RelativeLayout
и т.д.), Их атрибутах (например, android:layout_width
), id
ресурсов. Эти id
ресурсов относятся к реальным ресурсам в apk файле. Атрибуты разрешаются в значение во время выполнения. Процесс разрешения подходит для любого перенаправления (@dimen/...
вместо 4dp
или @color/...
в отличие от "#FFaabbcc"
) и возвращает используемое значение (значение dimen
разрешается не так, как значение color
).
Что такое скомпилированный XML файл: скомпилированный XML файл - это тот же XML файл, ссылки на ресурсы которого изменены на соответствующие ids
. Например, ссылка @string/ok
будет заменена на 0x7f000001
. Кроме того, атрибуты из пространства имен android
изменяются на их соответствующие целочисленные значения (например, wrap_content
изменяется на 0xfffffffe
или -2
)
Как Android разрешает ресурсы во время выполнения: метод inflater.inflate()
анализирует скомпилированный XML файл и создает иерархию представления путем создания экземпляров XML-узлов. Каждый из узлов xml создается классом java (например, LinearLayout.java, RelativeLayout.java). Чтобы создать экземпляр, инфлятор анализирует скомпилированный XML файл, собирает все атрибуты узла и создает упакованную структуру типа AttributeSet
. Этот AttributeSet
передается конструктору класса. Конструктор класса отвечает за обход AttributeSet
и разрешение каждого из значений атрибута.
Например, для макета, содержащего RelativeLayout
, inflater
будет упаковывать layout_width
и layout_height
в AttributeSet
и передавать его конструктору RelativeLayout (контекстный контекст, атрибуты AttributeSet, int defStyleAttr, int defStyleRes). В этом случае некоторые атрибуты и их значения разрешаются с помощью RelativeLayout.initFromAttributes(), а остальные - с помощью родительского ViewGroup.initFromAttributes().
android:id
представления - это просто еще один атрибут. Инфлятор хранит идентификатор каждого представления, вызывая setId(id)
для этого представления после создания экземпляра.
Теперь, чтобы ответить на ваш вопрос, R.id
- это массив java, а my_textview
- это целое число в этом массиве. id
представления my_textview
- это целое число (начинается с 0x7f). Метод findViewById()
выполняет поиск в глубину в этой иерархии представлений, чтобы найти соответствующее представление.
Надеюсь это поможет. Ссылка, которую вы указали в своем вопросе, уже отвечает на то, как aapt генерирует идентификаторы.
Это замечательная система управления ресурсами для устройств с различными вариациями. Более того, реализация действительно быстрая !! Основываясь на этом, он позволяет реализовать функциональность более высокого уровня (например, наложение ресурсов времени выполнения)
Ответ 2
LayoutInflater раздуть представление, используя XML-строки. XML-строки, скомпилированные в файл ресурсов, как вы упомянули в своем вопросе.
Пожалуйста, проверьте эти фрагменты кода AOSP:
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
Resources.getLayout
загружает XML-парсер ресурсов
public XmlResourceParser getLayout(int id) throws NotFoundException {
return loadXmlResourceParser(id, "layout");
}
XmlResourceParser loadXmlResourceParser(int id, String type)
throws NotFoundException {
synchronized (mAccessLock) {
TypedValue value = mTmpValue;
if (value == null) {
mTmpValue = value = new TypedValue();
}
getValue(id, value, true);
if (value.type == TypedValue.TYPE_STRING) {
return loadXmlResourceParser(value.string.toString(), id,
value.assetCookie, type);
}
throw new NotFoundException(
"Resource ID #0x" + Integer.toHexString(id) + " type #0x"
+ Integer.toHexString(value.type) + " is not valid");
}
}
getValue
использует AssetManager getResourceValue и он вызывает собственный метод loadResourceValue
. Этот собственный метод вызывает метод ResTable
getResource, чтобы получить строки XML, хранящиеся в файле ресурсов.
Ответ 3
Use appt for android-sdk (ex:- /build-tools/27.0.3/aapt )
run given script and get resources.arsc file content
./aapt dump resources ./debug.apk
Package Groups (1)
Package Group 0 id=0x7f packageCount=1 name=com.dianping.example.activity
Package 0 id=0x7f name=com.dianping.example.activity
type 1 configCount=3 entryCount=1
spec resource 0x7f020000 com.example.activity:drawable/ic_launcher: flags=0x00000100
config mdpi-v4:
resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000000 (s=0x0008 r=0x00)
config hdpi-v4:
resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000001 (s=0x0008 r=0x00)
config xhdpi-v4:
resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000002 (s=0x0008 r=0x00)
type 2 configCount=1 entryCount=1
spec resource 0x7f030000 com.dianping.example.activity:string/app_name: flags=0x00000000
config (default):
resource 0x7f030000 com.dianping.example.activity:string/app_name: t=0x03 d=0x00000003 (s=0x0008 r=0x00)
Эта ссылка может помочь http://elinux.org/Android_aapt