Wie funktioniert die Zuordnung zwischen Android-Ressourcen und Ressourcen-ID?

77

Es ist magisch für Android, die richtige Ressource nur über R.id.XXX zu finden .

AFAIK, die Ressourcen werden im Binärformat kompiliert. Wie funktioniert diese Zuordnungslogik unter der Haube?

Vielleicht funktioniert es so:

Zum Beispiel haben wir in der layout1.xml :

<Button android:id="@+id/button1" >

und AAPT wird dies in der R.java generieren:

public static final int button1=0x7f05000b;

Wenn die * .apk generiert wird, wird die @ + id / button1 durch "0x7f05000b" ersetzt.

Wenn wir also anrufen:

findViewById(R.id.button1);

Wir führen die Suche im Wesentlichen immer noch basierend auf der ID durch, obwohl die ID eine Zahl wie 0x7f05000b ist.

Vielen Dank!

HINZUFÜGEN

Was ich wirklich wissen möchte, ist, wie die Ressourcen-ID-Ganzzahl in den Ressourceninhalt analysiert wird. Mit anderen Worten, wie findet die Android-Laufzeit den Ressourceninhalt mit der Ressourcen-ID als einzigem Hinweis?

Wie wird beispielsweise ein zeichnbares Bild mit einer Ressourcen-ID gefunden? Oder wie wird ein Zeichenfolgenwert mit einer Ressourcen-ID gefunden?

smwikipedia
quelle

Antworten:

194

Zur Erstellungszeit sammelt das aapt-Tool alle von Ihnen definierten Ressourcen (obwohl separate Dateien oder explizite Definitionen in Dateien) und weist ihnen Ressourcen-IDs zu.

Eine Ressourcen-ID ist eine 32-Bit-Nummer des Formulars: PPTTNNNN. PP ist das Paket, für das die Ressource bestimmt ist. TT ist der Typ der Ressource; NNNN ist der Name der Ressource in diesem Typ. Für Anwendungsressourcen ist PP immer 0x7f.

Die TT- und NNNN-Werte werden von aapt willkürlich zugewiesen - grundsätzlich wird für jeden neuen Typ die nächste verfügbare Nummer zugewiesen und verwendet (beginnend mit 1); Ebenso wird für jeden neuen Namen in einem Typ die nächste verfügbare Nummer zugewiesen und verwendet (beginnend mit 1).

Wenn wir also diese Ressourcendateien von aapt in dieser Reihenfolge verarbeiten lassen:

layout/main.xml
drawable/icon.xml
layout/listitem.xml

Der erste Typ, den wir sehen, ist "Layout", also TT == 1. Der Vorname unter diesem Typ ist "main", also NNNN == 1. Die endgültige Ressourcen-ID lautet 0x7f010001.

Als nächstes sehen wir "zeichnbar", so dass TT == 2 gegeben wird. Der Vorname für diesen Typ ist "Symbol", so dass NNNN == 1 erhalten wird. Die endgültige Ressourcen-ID lautet 0x7f020001.

Zuletzt sehen wir ein anderes "Layout", das wie zuvor TT == 1 hat. Dies hat einen neuen Namen "listitem", so dass der nächste Wert NNNN == 2 erhalten wird. Die endgültige Ressourcen-ID lautet 0x7f010002.

Beachten Sie, dass aapt standardmäßig nicht versucht, diese Bezeichner zwischen Builds gleich zu halten. Jedes Mal, wenn sich die Ressourcen ändern, können sie alle neue Kennungen erhalten. Jedes Mal, wenn sie erstellt werden, wird eine neue R.java mit den aktuellen Bezeichnern erstellt, damit Ihr Code die richtigen Werte erhält. Aus diesem Grund dürfen Sie Ressourcen-IDs niemals an einem Ort beibehalten, an dem sie für verschiedene Builds Ihrer App verwendet werden können.

Sobald die Ressourcen kompiliert und Bezeichner zugewiesen wurden, generiert aapt die R.java-Datei für Ihren Quellcode und eine Binärdatei mit dem Namen "resources.arsc", die alle Ressourcennamen, Bezeichner und Werte enthält (für Ressourcen, die aus einer separaten Datei stammen Ihr Wert ist der Pfad zu dieser Datei in der APK-Datei in einem Format, das zur Laufzeit problemlos auf dem Gerät zugeordnet und analysiert werden kann.

Sie können eine Zusammenfassung der Datei resources.arsc in einer apk mit dem Befehl "aapt dump resources <Pfad-zu-apk>" erhalten.

Das Format der binären Ressourcentabelle ist in der Header-Datei für die Ressourcendatenstrukturen hier dokumentiert:

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

Die vollständige Implementierung zum Lesen der Ressourcentabelle auf dem Gerät finden Sie hier:

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

Hackbod
quelle
Übrigens, sind diese Details irgendwo dokumentiert?
smwikipedia
Die Implementierungsdetails sind außer den Strukturdefinitionen, auf die ich hier verweise, nicht dokumentiert.
Hackbod
1
Übrigens, IMHO, "RTFSC" ist falsch. Die Quelle ist eine Interpretation der Spezifikation und kann sich ändern. Wenn es keine Spezifikation gibt, ist das Verhalten offiziell undefiniert. Wenn Sie die Quelle lesen, erfahren Sie nur, was der Autor dachte, dass die Spezifikation zum Zeitpunkt des Schreibens bedeutete. Es sagt Ihnen, was jetzt passiert , aber nicht, was später passieren wird. Dennoch wird Diannes ausgezeichnete Erklärung Ihnen wahrscheinlich das geben, was Sie wissen müssen, und auf absehbare Zeit relevant bleiben.
Edward Falk
@ edward-falk: Ich denke, RTFSC ist hier richtig, da es sich bei der Frage an erster Stelle um Dinge unter der Haube handelt (die nie offiziell spezifiziert sind), nicht um API. Die interne Spezifikation ist der SC :)
port443
Werden Verweise auf Zeichenfolgen und andere Werte in XML zur Erstellung oder Laufzeit aufgelöst? <TextView text = "@ string / foo" />?
Jophde
5

Soweit ich weiß, generiert aapt automatisch eindeutige IDs für jede Ihrer Ressourcen und speichert sie in einer Nachschlagetabelle. Diese Nachschlagetabelle bleibt als "resources.arsc" -Datei in "bin / resources.ap_" erhalten (dies ist nur eine ZIP-Datei. Sie können sie also mit Ihrem bevorzugten ZIP-Viewer öffnen). Die Nachschlagetabelle wird auch als R.java beibehalten, sodass Sie, wie Sie wissen, auf Ihre Ressourcen in Java verweisen können.

Wenn Sie weitere Informationen zur ARSC-Datei wünschen, würde ich empfehlen, sie zu googeln oder den Code von http://code.google.com/p/android-apktool/ zu überprüfen .

-Dan

Dan
quelle
Danke für den wichtigen Hinweis. Ich werde eine Suche machen. Ich werde Ihre Antwort markieren, wenn keine bessere erscheint. Vielen Dank.
smwikipedia
1

Ein letzter Hinweis: Für die längste Zeit habe ich keine relativen Layouts verwendet, da viele Elemente auf Elemente weiter unten in der XML-Datei verweisen müssen, und ich wusste nicht, wie ich auf eine @ id / foo verweisen soll , die nicht definiert wurde noch.

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

Dann wurde mir eines Tages klar (duh), dass Sie eine ID in der Referenz definieren können ; es muss nicht in dem Element sein, das die ID trägt:

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

Die Magie liegt im Eclipse-Plug-In und der R.java-Datei, die automatisch im Ordner "gen" einer App generiert wird. Wenn Sie in diese Datei schauen, sehen Sie statische Zuordnungen für jedes XXX in R.xx.XXX, wobei xx Anim, Array, Farbe und jeder andere Ressourcentyp sein kann.

ErikR
quelle