web-dev-qa-db-fra.com

Ressources compilées Android - resources.arsc

J'essaie de comprendre ce que signifie "compiler des ressources".

Ce que j'ai fait pour comprendre ce problème:

J'ai lu de nombreux articles sur le sujet, mais je n'ai pas trouvé de réponse simple ... Le meilleur que j'ai lu était celui-ci: Comment le mappage entre les ressources Android et l'ID de ressources fonctionne-t-il? .

Comment je le comprends

Si je comprends bien, lorsque nous compilons notre projet par ANT (Eclipse) ou par Gradle (AS), nous utilisons un outil appelé aapt - Android Asset Packaging Tool qui: Est utilisé pour générer des identifiants uniques. Pour chacune de nos ressources, telles que nos mises en page, nos styles, etc., stockez-les dans une table de correspondance. Ensuite, il conserve cette table de recherche en générant deux fichiers:

  1. Il génère le fichier R.Java avec ces identifiants uniques afin que nous puissions utiliser nos ressources à partir de notre code Java lors de la compilation. 
  2. Il génère le fichier resources.arsc qui peut être trouvé dans le fichier resources * .ap_ . Ce fichier resources.arsc sera ensuite compressé par apktool vers apk.
    Ce format de fichier arsc est un format qui sera facilement mappé et analysé par le périphérique au moment de l’exécution.

Un exemple:

Donc, pour simplifier les choses: disons que cela se trouve dans activity_main.xml:

    <TextView Android:id="@+id/my_textView"
        Android:text="@string/hello_world" 
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content" />

Et je l’appelle depuis mon onCreate en utilisant:

findViewById(R.id.my_textView)

Dans mon fichier R.Java, je verrai:

public static final int my_textView=0x7f08003f;

Using: aapt dump resources sur l'apk généré, je vois qu'il contient deux lignes avec my_textView: Ressource ec 0x17f08003f com.example.lizi.liortest2: id/my_textView: flags = 0x00000000 .__ ressource 0x7f08003f com.example.lizi .liortest2: id/my_textView: t = 0x12 d = 0x00000000 (s = 0x0008 r = 0x00)

Ce que je ne comprends pas:

J'aurais pensé que ce fichier resources.arsc contiendrait non seulement l'ID de la ressource, mais également toutes les propriétés que j'ai définies pour la vue, telles qu'Android: layout_width = "wrap_content".

Alors maintenant, pendant l'exécution, lorsque VM tente d'exécuter findViewById(R.id.my_textView)Comment sait-il quelle vue obtenir/ses propriétés à créer?

Je ne comprends tout simplement pas comment cela fonctionne ... Cette table de recherche ne devrait-elle pas contenir aussi les données de propriétés? Et quel est ce nombre 0x7f08003f? (Devrait-il représenter une valeur qui sera ensuite mappée à la mémoire physique dans laquelle l'objet sera stocké?)

23
ZiviMagic

TL; DR: avec l'aide du compilateur Android (aapt), les nœuds XML seront traduits en classes Java et les attributs correspondants en identificateurs numériques. Le moteur d'exécution Android utilise ces identifiants pour instancier des classes afin de créer les vues

Longue réponse

Exécutez cette commande pour vider le fichier XML binaire
aapt d xmltree apk_file_name res/layout/activity_main.xml (aapt se trouve dans Android-sdk-dir/build-tools/23.0.2/aapt.exe)

Cela affichera les nœuds XML (par exemple, LinearLayout, RelativeLayout, etc.) avec leurs attributs (par exemple, Android:layout_width, Android:layout_height) et leurs valeurs. Notez que vous pouvez y voir les constantes match_parent (valeur numérique 0xffffffff ou -1) ou wrap_content (valeur numérique 0xfffffffe ou -2).

En fait, vous pouvez utiliser cette commande sur tout autre fichier xml de l'apk, par exemple. AndroidManifest.xml or layout files

Le fichier apk est juste une archive Zip contenant tous les fichiers de classe Java (classes.dex), tous les fichiers de ressources compilés et un fichier nommé resources.arsc. Ce fichier resource.arsc contient toutes les méta-informations sur les ressources, les nœuds xml (par exemple: LinearLayout, RelativeLayout, etc), leurs attributs (par exemple Android:layout_width), la ressource id '. Ces ressources id 'font référence aux ressources réelles du fichier apk. Les attributs sont résolus en une valeur au moment de l'exécution. Le processus de résolution est intelligent pour toute re-direction (@dimen/... par opposition à 4dp ou @color/... par opposition à "#FFaabbcc") et renvoie une valeur utilisable (une valeur dimen est résolue différemment d’une valeur color.). 

Ce qui est un fichier XML compilé: Un fichier XML compilé est exactement le même fichier XML avec les références de ressources modifiées en leur ids correspondante. Par exemple, une référence @string/ok sera remplacée par 0x7f000001. De plus, les attributs de l'espace de noms Android sont remplacés par leurs valeurs entières respectives (par exemple, wrap_content est remplacé par 0xfffffffe ou -2). 

Comment Android résout les ressources au moment de l'exécution: La méthode inflater.inflate() analyse un fichier XML compilé et crée une hiérarchie de vues en instanciant les nœuds xml. Chacun des nœuds XML est instancié par une classe Java (par exemple, LinearLayout.Java, RelativeLayout.Java). Pour instancier, inflater analyse le fichier XML compilé, collecte tous les attributs d'un nœud et crée une structure compacte de type AttributeSet . Cette AttributeSet est transmise au constructeur de la classe. Le constructeur de classe a la responsabilité de parcourir la AttributeSet et de résoudre chacune des valeurs d'attribut.

Par exemple, pour une présentation contenant RelativeLayout, la inflater encapsulera layout_width et layout_height dans un AttributeSet et sera transmise au constructeur RelativeLayout (contexte de contexte, AttributeSet attrs, int defStyleAttr, int defStyleRes) . Dans ce cas, certains des attributs et leurs valeurs sont résolus par (RelativeLayout.initFromAttributes () _ et le reste par le parent ViewGroup.initFromAttributes () .

Android:id d'une vue n'est qu'un autre attribut. L'inflater stocke l'identifiant de chaque vue par appelant setId(id) sur cette vue après l'instanciation.

Maintenant, pour répondre à votre questionR.id est un tableau Java et my_textview est un entier de ce tableau. La id de la vue my_textview est cet entier (commençant par 0x7f). La méthode findViewById() effectue une recherche en profondeur sur cette hiérarchie de vues pour trouver la vue correspondante.

J'espère que cela t'aides. Le lien que vous avez fourni dans votre question indique déjà comment les identifiants sont générés par aapt.

C'est un système merveilleux de gestion des ressources pour les appareils avec de multiples dimensions de variations. De plus, la mise en place est vraiment rapide !! Avec ceci comme base, cela permet d’implémenter des fonctionnalités de plus haut niveau (par exemple, recouvrement de ressources d’exécution ).

23
pellucide

LayoutInflater gonfle la vue en utilisant des chaînes XML. Les chaînes XML compilées dans un fichier de ressources, comme vous l'avez mentionné dans votre question.

Veuillez vérifier ces extraits de code d’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 charge l'analyseur de ressources 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 utilise getResourceValue de AssetManager et appelle la méthode native loadResourceValue. Cette méthode native appelle la méthode ResTable's getResource pour obtenir les chaînes XML stockées dans un fichier de ressources.

2
Wonil
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)

Ce lien pourrait aider http://elinux.org/Android_aapt

0