天天看點

Android資源管理架構-------之資源管理的基本資料結構和Bag資源(四)

資源管理的基本資料結構

        上一篇我們介紹了resources.arsc以及與之相關的主要資料結構,這些資料結構大多以ResTable_開頭,主要是用來描述resources.arsc非常友善。不過,要用這些資料結構來對Android資源進行管理,還是有些吃力,Android為了更加友善地管理資源,還有另外一套資料結構,它們主要是

ResTable

ResTable

的内部類。

        與resources.arsc相關的資料結構當中,最主要的是

ResTable_package

ResTable_type

ResTable_entry

這三級架構,也和資源id形式0xpptteeee(pp表示最高的一個位元組表示包id,第二高的一個位元組表示type id,最後兩個位元組表示entry id)相一緻。但是,要對實作對這三級資源架構的管理,要依靠的絕對不僅僅是這三級。确切地說,Android資源管理中用到,但是resources.arsc中沒有用到資料結構,主要是

ResTable

ResTable::PackageGroup

ResTable::Package

ResTable::TypeList

ResTable::Type

ResTable::Entry

。其中,

ResTable::Package

ResTable::Entry

ResTable_package

ResTable_entry

對應;

ResTable::Type

ResTable_type

的意義完全不一樣;

ResTable

ResTable::PackageGroup

ResTable::TypeList

是resources.arsc中沒有類似的資料結構與之對應。我們這裡再着重說一下,

ResTable_

開頭的資料結構偏重于對resources.arsc的描述,而

ResTable::

系列的資料結構是用來對資源資訊進行管理的,AssetManager中的許多接口功能的實作都要依賴它們。

ResTable

        Android資源管理架構-------之Android中的資源包(二)中,我們知道一個AssetManager可能會加載許多資源包,包括Android系統資源包也就是framework-res.apk、Soc廠商資源包、手機廠商資源包以及App本身,甚至還有可能存在overlay包、資源共享庫等等。那麼這些資源包中的resources.arsc加載後被存到了哪裡呢?最終它們都會被存放到一個

ResTable

的對象中,并且這個對象是native層

AssetManager

的一個成員。也就是說,一個

ResTable

對象會存儲它所在的AssetManager加載的所有資源包中的resources.arsc,并且對這些resources.arsc做統一的管理,這一點我們一定要注意。

//frameworks/base/include/androidfw/ResourceTypes.h
class ResTable
{
    //......省略無關代碼
    
    private:
    /**
    * 目前裝置配置資訊,我們去擷取資源時,要根據它來選擇合适的資源
    * 我們給AssetManager設定或者更新配置資訊時,最終也會存在這裡
    */
    ResTable_config             mParams;
    /**
    * 存放我們加載的所有資源包中的resources.arsc
    * 當然它不會把整個resources.arsc都放進來,隻是放入了每個resources.arsc的header資訊
    * 這樣通過header我們可以通路整個resources.arsc
    */
    Vector<Header*>             mHeaders;
    
    //我們加載過來的資源包相關的資訊都會放到這個資料結構中
    Vector<PackageGroup*>       mPackageGroups;
    /**
    * 這是一個Map,key為下标,具體為加載的package的id,
    * value為,這個package在mPackageGroups中的索引 + 1
    */
    uint8_t                     mPackageMap[256];
    
    //配置設定給下一個資源共享庫的臨時PackageId
    uint8_t                     mNextPackageId;
}
           

        我們看到一個内部,存儲的關鍵資訊就三個:

mParams

存儲配置資訊、

mHeaders

存儲加載的resources.arsc、mPackageGroups存儲加載的資源包相關的資訊。如果不考慮Runtime Resources Overlay,一個id為

packageId

的資源包的資訊為

mPackageGroups[mPackageMap[packageId] - 1]

。另外,在resources.arsc中,資源共享庫的packageId都是0,是以加載的時候要為它們動态配置設定一個id,mNextPackageId就是做這個用的。

ResTable::PackageGroup

        按照一般的邏輯,一個

ResTable

對象中直接存放一個

ResTable::Package

的集合就可以了,為什麼我們看到的卻是存放了一個

ResTable::PackageGroup

的集合呢?并且從

ResTable::PackageGroup

的實作來看它的内部确确實實又是存在多個

ResTable::Package

的,這個怎麼了解呢?

//frameworks/base/lib/androidfw/ResourceTypes.cpp
struct ResTable::PackageGroup
{

    //......省略無關代碼

    //這個PackageGroup所屬的ResTable
    const ResTable* const           owner;

    /**
    * 這個PackageGroup的name,為這個PackageGroup中第一個Package的name
    */
    String16 const                  name;
    uint32_t const                  id;

    //這個PackageGroup内的所有Package
    Vector<Package*>                packages;
    /**
    * 每一個元素都代表一種類型的資源
    * 當我們通路資源時,是通過PackageGroup到TypeList,再到Type,再到Entry
    * 中間并不會經過上面的packages變量
    */
    ByteBucketArray<TypeList>       types;

    //最大typeId
    uint8_t                         largestTypeId;

    //這個PackageGroup所有的bag資源,這個後面會單講,現在可以先無視之
    ByteBucketArray<bag_set**>*     bags;

    //資源共享庫相關的資料結構
    DynamicRefTable                 dynamicRefTable;
}
           

        其實,

ResTable::PackageGroup

的存在,是為了Runtime Resources Overlay(簡稱RRO),一般情況下一個

ResTable::PackageGroup

裡隻會有一個

ResTable::Package

,包括我們的應用包(id:0x7f)、系統資源包(id:0x01)、Soc廠商資源包、手機廠商資源包以及資源共享庫包等等。但是有RRO時,系統會把target包和overlay包放到同一個

ResTable::PackageGroup

中,以便擷取資源時可以快速地定位overlay包中的資源。并且target包會被放到

packages[0]

,overlay包則會放到後面,這個

ResTable::PackageGroup

的包名和id都會以target包為準。

ResTable::TypeList

//frameworks/base/include/androidfw/ResourceTypes.h

typedef Vector<Type*> TypeList;
           

ResTable::TypeList

的定義非常簡單。我們前面說過,通路資源時,通過

ResTable::PackageGroup

,到

ResTable::TypeList

,再到

ResTable::Type

,再到

ResTable::Entry

。我們看到,

ResTable::PackageGroup

types

成員是一個數組,這個數組中的每一個元素也就是

ResTable::TypeList

代表一種特定類型的資源,比如drawable、string等。但是,

ResTable::TypeList

本身又是一個

ResTable::Type

類型的數組,這個我們又該怎麼了解呢?

ResTable::TypeList

裡的每一個

ResTable::Type

對應一個不同的配置嗎? No!實際情況是這樣的:

ResTable::TypeList

ResTable::PackageGroup

類似,也是為了處理Runtime Resources Overlay。一般情況下,它的裡面也是隻有一個元素的,當有RRO的時候,我們可以通過下面的例子來了解:

//target package
 <resources>
     ......
    
     <string name="app_greeting">Goog Morning</string>
     <string name="app_appologize">Sorry</string>
     
      ......
</resources>

// overlay package
<resources>
     <string name="app_greeting">Goog Night</string>
</resources>
           

        在這個例子中,我們試圖通過overlay package來改變字元串

app_greeting

的值。那麼,在加載完target package後,overlay package也會被加載到 target package所在的ResTable中,并且會和target package放到同一個

ResTable::PackageGroup

中。并且,overlay package中的所有string類型的資源都會被系統放到target package中的string類型的資源所在的

ResTable::TypeList

中。也就是說 overlay package和target package中相同類型的資源,會被放到同一個

ResTable::TypeList

中,隻不過,target package中的資源會放在頭一個元素的位置,overlay package的放到後面。這樣做,可以很友善地把target package和overlay package中的資源組織到一起,通路也友善。

ResTable::Package

//frameworks/base/lib/androidfw/ResourceTypes.cpp
struct ResTable::Package
{
    //......省略無關代碼

    //所屬的ResTable
    const ResTable* const           owner;
    //對應的resources.arsc
    const Header* const             header;
    //對應的resources.arsc中的ResTable_package
    const ResTable_package* const   package;
    // Type String Pool
    ResStringPool                   typeStrings;
    // Key String Pool
    ResStringPool                   keyStrings;
    //......省略無關代碼
}
           

        通常一個ResTable::Package就會對應一個resources.arsc了。并且它裡面還會記錄這個resources.arsc中關鍵的資料塊,比如

ResTable_package

、Type String Pool、Key String Pool等。

ResTable::Type

ResTable::Type

的意義和

ResTable_type

完全不同。我們前文講過

ResTable_type

表示resources.arsc中某種配置下的某類型的所有資源,而

ResTable::Type

則表示一個包中某種類型的所有資源。注意,是某種類型的所有資源,包括所有配置!其實從這個角度來講,它倒是更像

ResTable_typeSpec

,我們看看

ResTable::Type

的實作:

//frameworks/base/lib/androidfw/ResourceTypes.cpp

struct ResTable::Type
{
    Type(const Header* _header, const Package* _package, size_t count)
        : header(_header), package(_package), entryCount(count),
          typeSpec(NULL), typeSpecFlags(NULL) { }
    //所屬的resources.arsc
    const Header* const             header;
    //所屬的資源包
    const Package* const            package;
    //資源項的個數
    const size_t                    entryCount;
    //資源對應的ResTable_typeSpec
    const ResTable_typeSpec*        typeSpec;
    //flags
    const uint32_t*                 typeSpecFlags;
    //RRO相關的資料結構
    IdmapEntries                    idmapEntries;
    //表示不同配置下的所有資源了
    Vector<const ResTable_type*>    configs;
};
           

        我們看到,一個

ResTable::Type

中包含多個

ResTable_type

,并且對于這個

ResTable_type

集合對象的命名也叫configs。自然,它裡面的每一個元素就對應一種配置了。

ResTable::Entry

ResTable::Entry

ResTable_entry

的差別倒不大,隻不過是對後者又做了進一步的封裝,添加了它所屬的類型、Package等資訊。

//frameworks/base/lib/androidfw/ResourceTypes.cpp

struct ResTable::Entry {
    //所屬ResTable_type的配置
    ResTable_config config;
    //對應的ResTable_entry
    const ResTable_entry* entry;
    //所屬的ResTable_type
    const ResTable_type* type;
    uint32_t specFlags;
    //所屬的Package
    const Package* package;
 
    //所屬的類型的名字在Type String Pool中的索引 
    StringPoolRef typeStr;
    //該資源項的名字在Key String Pool中的索引
    StringPoolRef keyStr;
};
           

        另外,還有幾個資料結構也值得一說,先看

ResTable::Header

//frameworks/base/lib/androidfw/ResourceTypes.cpp

struct ResTable::Header
{
    Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
        resourceIDMap(NULL), resourceIDMapSize(0) { }

    ~Header()
    {
        free(resourceIDMap);
    }
    //所屬的ResTable對象
    const ResTable* const           owner;
    //用來存儲整個resources.arsc,預設情況下這個是NULL,不會使用
    void*                           ownedData;
    //用來存儲整個resources.arsc的頭部
    const ResTable_header*          header;
    //整個resources.arsc中資料的大小
    //size = header->size
    size_t                          size;
    //整個resources.arsc的結尾位址
    const uint8_t*                  dataEnd;
    /**
    * 該resources.arsc或者說該資源包在owner對象中的索引
    * 或者說是該header對象在ResTable::mHeaders中的索引
    * 都是一會事兒
    */
    size_t                          index;
    /**
    * 該資源包是owner對象加載的第幾個資源包,從1開始
    * 一般cookie = index + 1
    */
    int32_t                         cookie;
    //resources.arsc的Key String Pool
    ResStringPool                   values;
    //資源共享庫相關
    uint32_t*                       resourceIDMap;
    //資源共享庫相關
    size_t                          resourceIDMapSize;
};
           

        我們看到

ResTable::Header

内部的資料結構,大都是resources.arsc相關的,也就是說,它主要用來在資源管理的過程中來描述一個resources.arsc,而通常一個資源包對應一個resources.arsc,是以也可以了解為它和一個資源包是一一對應的。這裡的index成員好了解,cookie我們簡單說明以下。在Android的資源管理架構中cookie的出現頻率極高,不過它們的含義基本一緻,都是代表一個資源包或者說一個resources.arsc或者說一個Key String Pool(它們三個是一一對應的)在它所屬的

ResTable

中的索引值(從1開始計數)。畢竟一個AssetManager也好,一個

ResTable

也好,它的内部都會存在多個資源包,當我們傳回一個資源資訊時,少不了要傳回這個資源所屬的資源包,這個就是cookie值了。

        再看下面兩個資料結構:

//frameworks/base/include/androidfw/ResourceTypes.h
struct ResTable_ref
{
    uint32_t ident;
};

struct ResStringPool_ref
{
    uint32_t index;
};
           

        首先這兩個資料結構不僅在進行資源管理的時候會用到,在resources.arsc中也會用到。其中

ResTable_ref

,表示一項資源的引用,32位整型值就是形如0xpptteeee的一個id,跟R檔案中的id一模一樣,也就是說,它實際上指向了另一個資源的id。從這裡我們也可以看到,android的資源管理是支援資源引用的,這在我們使用資源的時候将會非常非常友善,但缺點是,當我們擷取資源時,如果結果的類型是TYPE_REFERENCE,我們擷取到的将不會是最終的結果,如果想得到最終的具體值,則需要增加對引用的解析這個步驟。而

ResStringPool_ref

則是一個字元串在

ResStringPool

中的索引。通常當我們要通路的資源是一個字元串的時候,Android資源管理架構的native層不會直接傳回一個字元串,而是傳回一個

ResStringPool_ref

和一個cookie值,前者表示索引,後者表示結果字元串哪個

ResStringPool

中,然後我們根據索引到對應的

ResStringPool

中就可以拿到具體的結果了。

        我們畫一張圖來描述相關的資料結構:

Android資源管理架構-------之資源管理的基本資料結構和Bag資源(四)

        我們看到,這張圖中少了

Restable::Entry

,因為它可以看做是對

Restable:_entry

的封裝,它的存在是為了我們從上層更加友善地get資源。不過,它卻是是遊離于

ResTable

ResTable::PackageGroup

ResTable::Package

ResTable::TypeList

ResTable::Type

之外的,它們都沒用引用

Restable::Entry

AssetManager

AssetManager

是native層資源管理的接口,它實際上是對

ResTable的封裝

,我們可以粗略地認為,

AssetManager

負責加載資源包,并從中解壓出各種資源檔案,特别是resources.arsc,然後将它丢給

ResTable

,後面的事兒就由

ResTable

負責了。

AssetManager

在管理資源包的過程中用到的

AssetDir

Asset

_FileAsset

_CompressedAsset

等資料結構,我們可以看做是對一般目錄、檔案、壓縮包的封裝;

AssetManager::SharedZip

AssetManager::ZipSet

,則是為了友善我們對APK包的通路以及緩存。這些資料結構算是資源管理的工具吧,它們和資源管理本身關系不大,我們這裡一句帶過了。

//frameworks/base/include/androidfw/AssetManager.h

#ifdef __cplusplus
extern "C" {
#endif

struct AAssetManager { };

#ifdef __cplusplus
};
#endif

class AssetManager : public AAssetManager {

     //.....省略次要代碼

     //加載的資源包的路徑
     Vector<asset_path> mAssetPaths;
     //ResTable
     mutable ResTable* mResources;
     //配置資訊
     ResTable_config* mConfig;
     
     //.....省略次要代碼
}
           

        到這裡,Android資源管理相關的底層的主要資料結構我們已經介紹的差不多了,當然Runtime Resources Overlay、資源共享庫相關的資料結構我們沒有介紹,如果大家有興趣,點開連接配接可以詳細了解它們的實作和原理。還有就是XML相關的資料結構,它們比較獨立,和Android資源管理關系不是那麼不可分割,有機會我們可以搞個專題。在這裡我們注意區分開

ResTable_

ResTable::

打頭的資源即可:前者大多用來描述resources.arsc;後者用于資源管理的邏輯的實作。當然

ResTable_config

ResTable_ref

、ResStringPool等,在描述resources.arsc和管理資源時都會用到。

Bag資源

        我們前面講資源項的時候說到,一般情況下,一個資源項其實是一個鍵值對兒:鍵表示資源項的名字,用

ResTable_entry

表示;值表示資源項的相關資訊(具體值或者資源的路徑等等),用

Res_value

表示。但是還有二般情況,有一些資源我們僅僅用一個鍵值對兒是描述不清的,比如style類型的資源:

<resources>

    .......
    
    <style name="WorkspaceIcon">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">match_parent</item>
        <item name="android:layout_gravity">center</item>
        <item name="android:gravity">center_horizontal</item>
        <item name="android:singleLine">true</item>
        <item name="android:ellipsize">end</item>
        <item name="android:textSize">@dimen/workspace_icon_text_size</item>
        <item name="android:textColor">@color/workspace_icon_text_color</item>
        <item name="android:shadowRadius">2.0</item>
        <item name="android:shadowColor">#B0000000</item>
    </style>

    <style name="WorkspaceIcon.Portrait">
        <item name="android:drawablePadding">@dimen/app_icon_drawable_padding</item>
        <item name="android:paddingStart">4dp</item>
        <item name="android:paddingEnd">4dp</item>
        <item name="android:paddingTop">@dimen/app_icon_padding_top</item>
        <item name="android:paddingBottom">4dp</item>
    </style>

    ......

</resources>
           

        我們看style

WorkspaceIcon.Portrait

,抛開它的parent style

WorkspaceIcon

不談,它的名稱似乎可以用一個

ResTable_entry

來表示,但是它的值我們可以用一個

Res_value

表示嗎?顯然不能!!!

        這個style的值不是一個簡單的值,而是由5個鍵值對兒組成:

android:drawablePadding   --->  @dimen/app_icon_drawable_padding
 android:paddingStart   --->  4dp
 android:paddingEnd   --->  4dp
 android:paddingTop   ---> @dimen/app_icon_padding_top
 android:paddingBottom   ---> 4dp
           

        對于類似style的這種資源,既然不能使用

ResTable_entry

+

Res _value

來表示,那就隻能使用新的資料結構了,也就是

ResTable_map_entry

ResTable_map

//frameworks/base/include/androidfw/ResourceTypes.h
struct ResTable_map_entry : public ResTable_entry
{
   // Resource identifier of the parent mapping, or 0 if there is none.
   // This is always treated as a TYPE_DYNAMIC_REFERENCE.
   ResTable_ref parent;
   // Number of name/value pairs that follow for FLAG_COMPLEX.
   uint32_t count;
};
           

        我們看到

ResTable_map_entry

繼承了

ResTable_entry

,并且添加了兩個新的字段,分别來表示它的父style和item的個數。

//frameworks/base/include/androidfw/ResourceTypes.h
struct ResTable_map
{
     //表示鍵值對兒中的鍵
     ResTable_ref name;

     //......省略次要代碼
     
     //表示鍵值對兒中的值
     Res_value value;
}
           

        在一個resources.arsc中,一個

ResTable_map_entry

後面會跟

ResTable_map_entry::count

ResTable_map

。具體到這個例子當中:

ResTable_map_entry::size = 16		/*16個位元組*/

//FLAG_COMPLEX表示這個結構體後面跟的不再是簡單的Res_value,而是一個個的mapping
ResTable_map_entry::flags = FLAG_COMPLEX

//key 是我們這個style的名字,當然這裡是WorkspaceIcon.Portrait在key string pool中的索引
ResTable_map_entry::key = "WorkspaceIcon.Portrait"在key string pool中的索引

//parent 當然是WorkspaceIcon這個style了
ResTable_map_entry::parent = WorkspaceIcon這個style的id

//後面跟的鍵值對兒的個數,也就是style的item的個數
ResTable_map_entry::count = 5

//後面會有5個ResTable_map,它們的值分别為:

/*ResTable_map::value的類型是Res_value, 我們為了友善,在這裡隻寫出了其data字段,沒有列出其data_type等其它字段*/
ResTable_map::name = android:drawablePadding的id        ResTable_map::value = dimen/app_icon_drawable_padding的id
ResTable_map::name = android:paddingStart的id        ResTable_map::value = 4dp
ResTable_map::name = android:paddingEnd的id        ResTable_map::value = 4dp
ResTable_map::name = android:paddingTop的id        ResTable_map::value = dimen/app_icon_padding_top的id
ResTable_map::name = android:paddingBottom的id        ResTable_map::value = 4dp
           

         以上的結構非常好了解,我們用一個一個的鍵值對兒來描述一項比較複雜的資源,這每一個鍵值對兒就叫該資源的一個Bag。也就是說,style的每一個item都是style的Bag。我們的style

WorkspaceIcon.Portrait

自身有5個Bag,它的parent style

WorkspaceIcon

有10個Bag,并且不存在覆寫的情況,是以style

WorkspaceIcon.Portrait

總共有15個Bag。

         當然,擁有Bag的資源不隻style一種,除此之外,還有bag、plurals、array、string-array、integer-array、attr共7種。

         bag類型的資源隻在aapt中有定義,無論是Android 系統源碼還是一般應用當中都還沒有發現使用,這裡就不說了。

         array、string-array、integer-array這三種資源差不多可以看成一種。一個array同樣會包含多個item,比如:

<array name="sim_colors">
    <item>@color/Teal_700</item>
    <item>@color/Blue_700</item>
    <item>@color/Indigo_700</item>
    <item>@color/Purple_700</item>
    <item>@color/Pink_700</item>
    <item>@color/Red_700</item>
</array>
           

        大家有沒有發現和style不一樣的地方?style的每一個item都是一個鍵值對兒,但是array的每一個item都隻有值,并沒有鍵!!!array的item表面上确實沒有鍵,但其實它是有的,那就是索引,也就是每一個item在array中的位置或者說順序。并且aapt在編譯array(包括string-array和integer-array)的時候,會同時記錄其索引的,并且這個索引用^index_%d來表示,其中%d表示索引值,比如0、 1 、2…

        plurals大家應該也經常接觸,它主要用來處理多語言環境下,字元串的單複數形式:

<plurals name="copy_begin">
        <item quantity="one">Copying <xliff:g id="count" example="1">%1$d</xliff:g> file.</item>
        <item quantity="other">Copying <xliff:g id="count" example="3">%1$d</xliff:g> files.</item>
    </plurals>
           

        比如這個,

quantity

的值自然就是key了,android中

quantity

的值總共可以取:^zero、 ^one、^two、^few、^many、^other六種。當然,不同的語言環境可能隻用其中的某一些,比如英語,隻有單複數,是以隻用^one、^other兩種,這個和具體的語言相關,這裡就不多說了。

        attr我們大家都非常熟悉了,它也有Bag資源?一個形如

<attr name="textAppearance" format="reference" />

的attr,一個

ResTable_entry

和一個

Res_value

似乎是夠了的。我們不急,先來看看這個attr:

<attr name="orientation">
        <!-- Defines an horizontal widget. -->
        <enum name="horizontal" value="0" />
        <!-- Defines a vertical widget. -->
        <enum name="vertical" value="1" />
    </attr>
           

        這個就是Android源生的orientation屬性的定義,它是一個枚舉類型,這時候一個

ResTable_entry

+ 一個

Res_value

顯然是不行的。其實,形如

<attr name="textAppearance" format="reference" />

的attr,用一個

ResTable_entry

+ 一個

Res_value

也是不行的,因為它的鍵值可以是這個屬性的名字textAppearance,但是值呢?顯然是某個資源的id,而不能是

reference

。事實上,format=“reference” 這一句,我們可以看作是對

textAppearance

這個attr的描述。當然,

<enum name="horizontal" value="0" />

和也一樣是對

orientation

這個attr的描述,表示它隻的值隻能是二者之一,而不能随意去取。aapt在編譯的時候,會把format也作為一個Bag記錄下來,表示這個attr的類型,并用^type來表示。我們再來看看另外完整版的

ResTable_map

//frameworks/base/include/androidfw/ResourceTypes.h
struct ResTable_map
{
    ResTable_ref name;
    
    enum {
        ATTR_TYPE = Res_MAKEINTERNAL(0),
        ATTR_MIN = Res_MAKEINTERNAL(1),
        ATTR_MAX = Res_MAKEINTERNAL(2),
        ATTR_L10N = Res_MAKEINTERNAL(3),
        ATTR_OTHER = Res_MAKEINTERNAL(4),
        ATTR_ZERO = Res_MAKEINTERNAL(5),
        ATTR_ONE = Res_MAKEINTERNAL(6),
        ATTR_TWO = Res_MAKEINTERNAL(7),
        ATTR_FEW = Res_MAKEINTERNAL(8),
        ATTR_MANY = Res_MAKEINTERNAL(9)
    };
    
    enum {
        TYPE_ANY = 0x0000FFFF,
        TYPE_REFERENCE = 1<<0,
        TYPE_STRING = 1<<1,
        TYPE_INTEGER = 1<<2,
        TYPE_BOOLEAN = 1<<3,
        TYPE_COLOR = 1<<4,
        TYPE_FLOAT = 1<<5,
        TYPE_DIMENSION = 1<<6,
        TYPE_FRACTION = 1<<7,
        TYPE_ENUM = 1<<16,
        TYPE_FLAGS = 1<<17
    };

    enum {
        L10N_NOT_REQUIRED = 0,
        L10N_SUGGESTED    = 1
    };

    Res_value value;
};
           

        我們看到,它裡面有三個枚舉類型的資料,它們是做什麼的呢?最後一個顯然是本地化相關的,我們不做讨論。我們先說第一個,當我們的資源是attr的時候,它們可以作為

ResTable_map::name

的值,用來描述這個attr相關的元資訊。比如,這個屬性的類型、最大取值、最取小值等等,當

ResTable_map::name

的值為

ATTR_TYPE

的時候,Res_value::data的值該是什麼呢?答案就是第二個enum中的值;當我們的資源是plurals的時候,它的Bag的key隻能是^zero、 ^one、^two、^few、^many、^other,值就是item當中的字元串;當我們的資源是array(包括string-array和integer-array)的時候,它的Bag的key隻能是^index_%d.

        Bag資源相關的東西我們就先介紹到這裡,後面講aapt的時候我們還會詳細講Bag資源的編譯。這裡我們隻需要知道什麼是Bag資源就可以了。