web-dev-qa-db-ja.com

Androidコンパイルされたリソース-resources.arsc

「リソースをコンパイルする」とはどういう意味かを理解しようとしています。

この問題を理解するために私がしたこと:

私はこの主題について多くの記事を読みましたが、簡単な答えは見つかりませんでした。私が読んだ最高のものはこれでした: AndroidリソースとリソースID間のマッピングはどのように機能しますか?

私の理解:

私の理解では、ANT(Eclipse)またはGradle(AS)でプロジェクトをコンパイルするとき。 aapt-Android Asset Packaging Toolというツールを使用します。レイアウト、スタイルなどのリソースをルックアップテーブルに格納し、2つのファイルを生成してこのルックアップテーブルを永続化します。

  1. これらの一意のIDでR.Javaファイルを生成するため、コンパイル中にJavaコードからリソースを使用できます。
  2. Resources * .ap_ファイルにあるresources.arscファイルを生成します。この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;
_

使用:生成されたapkのaaptダンプリソースには、my_textViewの2行が含まれています: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ファイルには、リソースIDだけでなく、Android:layout_width = "wrap_content"など、ビューに定義したすべてのプロパティも含まれると考えていました。

では、実行中にVMがfindViewById(R.id.my_textView)を実行しようとすると、どのビューを取得するか、そのプロパティを作成するかをどのように知るのでしょうか?

私は単にそれがどのように機能するか理解できません...このルックアップテーブルにはプロパティデータも含まれるべきではありませんか?そして、この0x7f08003f番号は何ですか? (オブジェクトが格納される物理メモリに後でマップされる値を表す必要がありますか?)

28
ZiviMagic

TL; DR:Android compiler(aapt)xmlノードは、Javaクラスと、数値IDに対応する属性に変換されます。Androidランタイムはこれらで動作しますビューを作成するためにクラスをインスタンス化するID

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ノード(例:LinearLayoutRelativeLayoutなど)とその属性(_Android:layout_width, Android:layout_height_)および値が表示されます。定数_match_parent_(数値_0xffffffff_または_-1_)または_wrap_content_(数値_0xfffffffe_または_-2_)が表示されることに注意してください。

実際のところ、apkの他のxmlファイルでこのコマンドを使用できます。 _AndroidManifest.xml or layout files_

Apkファイルは、すべてのJavaクラスファイル(_classes.dex_)、すべてのコンパイル済みリソースファイル、および_resources.arsc_という名前のファイルを含むZipアーカイブです。この_resource.arsc_ファイルには、リソースに関するすべてのメタ情報が含まれています。

  • xmlノード(例:LinearLayoutRelativeLayoutなど)、
  • 属性(例、_Android:layout_width_)、
  • リソースid 's。

リソースidは、apkファイル内の実際のリソースを参照します。属性は実行時に値に解決されます。解決プロセスは、リダイレクト(_@dimen/..._ではなく_4dp_または_@color/..._ではなく_"#FFaabbcc"_)に対して賢く、使用可能な値(a dimen値は、color値とは異なる方法で解決されます)。

コンパイル済みXMLファイルとは:コンパイル済みXMLファイルは、リソース参照が対応するidsに変更された同じXMLファイルです。たとえば、参照_@string/ok_は_0x7f000001_に置き換えられます。さらに、Android名前空間の属性はそれぞれの整数値に変更されます(例:_wrap_content_は_0xfffffffe_または_-2_に変更されます)

How Android実行時にリソースを解決する:メソッド inflater.inflate() 解析するコンパイルされたxmlファイル。xmlノードをインスタンス化してビュー階層を作成します。各xmlノードはJava class(LinearLayout.Java、RelativeLayout.Java)などによってインスタンス化されます。インスタンス化するには、 inflaterは、コンパイルされたxmlファイルを解析し、ノードのすべての属性を収集し、 creates タイプのパック構造 AttributeSet 。このAttributeSetはクラスコンストラクターに渡されるクラスコンストラクターは、AttributeSetを調べて、各属性値を解決する責任があります。

たとえば、RelativeLayoutを含むレイアウトの場合、inflaterは_layout_width_および_layout_height_をAttributeSetにパックし、コンストラクターに渡します- RelativeLayout(コンテキストコンテキスト、AttributeSet attrs、int defStyleAttr、int defStyleRes) 。この場合、一部の属性とその値は RelativeLayout.initFromAttributes() で解決され、残りは親 ViewGroup.initFromAttributes() で解決されます。

ビューの_Android:id_は、単なる別の属性です。インフレータは、インスタンス化後にそのビューで setId(id)を呼び出す によって各ビューのIDを保存します

質問に答える_R.id_はJava配列で_my_textview_は整数ですビューのid _my_textview_はこの整数です(0x7fで始まります) findViewById() メソッドは、深さ優先検索を行いますそのビュー階層を使用して、それぞれのビューを見つけます。

お役に立てれば。質問で指定した link は、aaptによるIDの生成方法に既に回答しています。

さまざまな次元のバリエーションを持つデバイスのリソースを管理するすばらしいシステムです。さらに、実装は非常に高速です!!これを基盤として、より高いレベルの機能を実装することができます(例 Runtime Resource Overlay

27
pellucide

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");
    }
}

getValueAssetManagergetResourceValue を使用し、loadResourceValueネイティブメソッドを呼び出します。このネイティブメソッドは、ResTableの-​​ getResource メソッドを呼び出して、リソースファイルに格納されているXML文字列を取得します。

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)

このリンクは役立つかもしれません http://elinux.org/Android_aapt