Як працює зіставлення ресурсів Android та ідентифікаторів ресурсів?


77

Для 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 визначає вміст ресурсу з ідентифікатором ресурсу як єдиною підказкою?

Наприклад, як знайти зображення, яке можна малювати, з ідентифікатором ресурсу? Або як знайдено значення рядка з ідентифікатором ресурсу?

Відповіді:


194

Під час побудови інструмент 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 скинути ресурси <шлях- до- apk>".

Формат таблиці двійкових ресурсів задокументований у файлі заголовка для структур даних ресурсів тут:

https://github.com/android/platform_frameworks_base/blob/master/libs/androidfw/include/androidfw/ResourceTypes.h

Повна реалізація для читання таблиці ресурсів на пристрої знаходиться тут:

https://github.com/android/platform_frameworks_base/blob/master/libs/androidfw/ResourceTypes.cpp


До речі, чи десь задокументовані ці деталі?
smwikipedia

Деталі реалізації не задокументовані, крім визначень структури, на які я посилаюся тут.
hackbod

1
BTW, IMHO, "RTFSC" помиляється. Джерело є інтерпретацією специфікації і може змінюватися. Якщо специфікації немає, тоді поведінка офіційно не визначена. Читання джерела лише розповідає, що автор думав, що специфікація означала на момент написання. Він повідомляє вам, що відбувається зараз , але не те , що станеться пізніше. Все-таки чудове пояснення Діанни, мабуть, дасть вам те, що вам потрібно знати, і збереже актуальність у найближчому майбутньому.
Едвард Фальк

@ edward-falk: Я вважаю, що RTFSC тут правильний, оскільки питання насамперед стосується матеріалів, що не підпадають під капот (які ніколи офіційно не вказуються), а не API. Внутрішня специфікація - SC :)
port443

Чи посилання на рядки та інші значення в XML вирішуються під час побудови або виконання? <TextView text = "@ string / foo" />?
jophde

7

Якщо вас цікавить внутрішня реалізація (на стороні пристрою), подивіться на loadDrawable () у Resources.java . Інформацію про вилучення даних із таблиці ресурсів див. У чудовій відповіді hackbod

Щоб знати, як макети перекладаються у подання з ідентифікатора ресурсу, перегляньте LayoutInfater .java


5

Наскільки я розумію, aapt автоматично згенерує унікальні ідентифікатори для кожного з ваших ресурсів та збереже їх у пошуковій таблиці. Ця таблиця пошуку зберігається як файл "resources.arsc", розташований у "bin / resources.ap_" (це лише ZIP-файл, тому сміливо відкривайте його за допомогою улюбленого засобу перегляду ZIP). Таблиця пошуку також зберігається як R.java, що, як відомо, дозволяє посилатися на ваші ресурси в Java.

Якщо вам потрібна додаткова інформація про файл ARSC, я б запропонував його погуглити або переглянути код http://code.google.com/p/android-apktool/ .

-Дан


Дякую за важливу підказку. Я проведу обшук. Я позначу вашу відповідь, якщо не з’явиться кращої. Дякую.
smwikipedia

1

Останнє зауваження: найдовше я не використовував відносні макети, оскільки багато елементів мають посилатися на елементи нижче у файлі xml, і я не знав, як посилатися на @ id / foo, який не був визначений ще.

<!-- doesn't work -->
<TextView android:layout_above="@id/foo">above</textview>
<TextView android:id="@+id/foo">below</textview>

Потім одного разу я зрозумів (duh), що ви можете визначити ідентифікатор у посиланні; це не повинно бути в елементі, що має ідентифікатор:

<!-- works -->
<TextView android:layout_above="@+id/foo">above</textview>
<TextView android:id="@id/foo">below</textview>

0

Магія полягає в плагіні Eclipse та файлі R.java, який він автоматично генерує в папці "gen" додатка. Якщо ви заглянете в цей файл, ви побачите статичні зіставлення для кожного XXX у R.xx.XXX, де xx може бути анімом, масивом, кольором та будь-яким іншим типом ресурсу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.