《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 其他 > 設(shè)計(jì)應(yīng)用 > 深入理解Android之資源文件
深入理解Android之資源文件
Venus神廟的博客<
摘要: 作為一枚coder,做界面,很多時(shí)候都是一場(chǎng)夢(mèng)魘。很多時(shí)候,我們會(huì)感覺(jué)對(duì)于底層邏輯實(shí)現(xiàn)的很有把握性,哪怕需求一直在變,也可以通過(guò)不斷的重構(gòu)一直跟進(jìn),一切盡在掌握。但遭遇界面,往往就不再如此,它的好壞總是和審美、體驗(yàn)之類的詞匯扯在一起。
關(guān)鍵詞: Android 資源文件
Abstract:
Key words :

  作為一枚coder,做界面,很多時(shí)候都是一場(chǎng)夢(mèng)魘。很多時(shí)候,我們會(huì)感覺(jué)對(duì)于底層邏輯實(shí)現(xiàn)的很有把握性,哪怕需求一直在變,也可以通過(guò)不斷的重構(gòu)一直跟進(jìn),一切盡在掌握。但遭遇界面,往往就不再如此,它的好壞總是和審美、體驗(yàn)之類的詞匯扯在一起,在鳳姐芙蓉出沒(méi)的年頭,談審美成為一件恐怖的事情。你可能會(huì)被要求不停的改代碼,就為了移動(dòng)一個(gè)像素,調(diào)整一枚按鈕,瑣碎而無(wú)聊。

  為了改變這樣的狀況,挽救coder們于水生活熱之中,很多開(kāi)發(fā)平臺(tái),都采用了類似于資源文件的解決方案。此類方案的基本思想是,將界面的實(shí)現(xiàn)與底層邏輯的實(shí)現(xiàn)完全剝離開(kāi)來(lái),用資源文件這樣的東西來(lái)描述界面。資源文件的描述語(yǔ)言,往往是結(jié)構(gòu)化很強(qiáng),比如Html,Xml(及其變形體)之類的。于開(kāi)發(fā)語(yǔ)言相比,此類語(yǔ)言邏輯性較弱但結(jié)構(gòu)更好可讀性更強(qiáng)更容易理解,并對(duì)自動(dòng)化工具非常友好,可以于界面的拖拽配置結(jié)合的更加完美。這樣的剝離,可以是的底層邏輯和上層界面獨(dú)立變化,甚至不同的人員開(kāi)發(fā)(這一點(diǎn)在web開(kāi)發(fā)上表現(xiàn)的應(yīng)該很明顯。..),兩者之間的耦合性非常的小,coder們的負(fù)擔(dān),陡然減少(好吧,一個(gè)很挫的資源架構(gòu)也會(huì)額外增加開(kāi)發(fā)人員的負(fù)擔(dān),Symbian同學(xué),請(qǐng)不要對(duì)號(hào)入座。..)。

  結(jié)構(gòu)和格式

  Android的資源文件,是由目錄結(jié)構(gòu),Xml格式的文件,和純數(shù)據(jù)文件構(gòu)成。從格式上來(lái)看,無(wú)疑,學(xué)習(xí)門檻非常低。Xml作為coder們的瑞士軍刀,哪怕使不習(xí)慣,弄得清楚并會(huì)用至少是沒(méi)有問(wèn)題。從配套的工具來(lái)看,Android的ADT,提供了一套可視化的配置工具,說(shuō)不上特別好用,但至少是差強(qiáng)人意能湊合著用,比不上iPhone的,調(diào)戲Symbian還是沒(méi)有問(wèn)題的[強(qiáng)檔廣告首播:有道詞典 for iPhone新版火熱上線,增加了超強(qiáng)單詞本功能,特有的觸電式顫抖單詞切換功能,讓你欲罷不能,持有相關(guān)設(shè)備的童鞋不要猶豫,一擁而上吧。..]。

  Android的資源文件,覆蓋面超級(jí)廣,只要是和界面相關(guān)的,都可以用資源文件表示,比如:UI的樣式,菜單,配置文件,各種描述性字符串,圖片,音頻視頻文件,動(dòng)畫(huà),顏色,尺寸,風(fēng)格和樣式,等等等。所有的資源文件(不考慮asset,它和討論暫無(wú)關(guān)聯(lián)。..),都放在res目錄下,不同類別的資源,需要放置在不同的特定名稱的子文件夾中,或者是寫(xiě)在特定文件名的文件中(或者ms不是必須的,但,不用在這里特立獨(dú)行,尋章辦事也挺好。..)。比如,所有作為UI背景之類的圖片,都需要扔在drawable這類的文件夾中,所有字符串相關(guān)的,都會(huì)放到values目錄下形如strings.xml這樣的文件中(如下圖所示,是一個(gè)資源文件目錄結(jié)構(gòu)的截圖。..)。

  

  每個(gè)xml文件,都有一定的約定。比如一個(gè)字符串,會(huì)放在《string》《/string》這樣的xml element中(如下圖所示。..),你可以通過(guò)eclipse的ADT插件提供的可是界面去填而不關(guān)注具體規(guī)范,也可以直接人肉打造,前者對(duì)于新手來(lái)說(shuō)更為直觀,后者對(duì)于老鳥(niǎo)而言更為迅捷。

  

  可配置性

  程序邏輯總是不變應(yīng)萬(wàn)變的,但界面往往是需要能夠72變。首先一種變化因素,就是狀態(tài)。想象一下,我們往往會(huì)有這樣類似的需求,一個(gè)按鈕,我們需要沒(méi)有按下去的時(shí)候是一種背景,按的過(guò)程中刷的變成另一副模樣,當(dāng)它可用的時(shí)候需要鮮鮮亮的一個(gè)樣子,不可用的時(shí)候最好是灰不溜秋沒(méi)人愿點(diǎn)的慫樣,諸如此類。傳統(tǒng)編程模型下(Symbian,哥叫你出來(lái)當(dāng)模特。..),我們總是需要不厭其煩的用代碼控制這樣的事情。監(jiān)聽(tīng)不同的事件,見(jiàn)縫插針的切換背景,并祈禱上天,千萬(wàn)別讓哥調(diào)整,否則哥和你沒(méi)完。

  

  在Android中,做這個(gè)事情,變得簡(jiǎn)單許多,通過(guò)預(yù)設(shè)的一些Xml屬性,能夠輕松的搞定。如上圖所示,是Radio Button的背景。通過(guò)搭配不同的屬性,就可以自動(dòng)轉(zhuǎn)換背景。比如第一個(gè)《item》,說(shuō)的是當(dāng)Radio Button被選中,并且具有焦點(diǎn)的時(shí)候,顯示btn_radio_on這幅圖片,而最后一個(gè)《item》,說(shuō)的是前述條件都不滿足,并且處于選中狀態(tài),那么顯示btn_radio_on這幅圖片。

  另外一個(gè)更易變的因素,就是手機(jī)硬件/軟件環(huán)境了,畢竟,不是家家都是蘋(píng)果,一個(gè)平臺(tái)搭一款手機(jī),手機(jī)款形多樣化,幾乎是避免不了的問(wèn)題。沒(méi)有人希望自己做的軟件在大屏幕手機(jī)上閃亮光鮮,換個(gè)小屏幕就慘不忍睹,豎屏看像那么回事橫屏看就擠做一團(tuán)。還有就是語(yǔ)言環(huán)境了,做為一個(gè)有國(guó)際眼光的coder,作面向世界的NB軟件是咱的夢(mèng)想,但我們不能因?yàn)樽约旱膲?mèng)想逼迫大家都去學(xué)中文,做一款軟件可以根據(jù)手機(jī)的語(yǔ)言環(huán)境選擇最合適展示的語(yǔ)言,很多時(shí)候,是一個(gè)需要具備的功能點(diǎn)。

  在Android中,實(shí)現(xiàn)這些,都是舉手之勞。方法就是將和環(huán)境相關(guān)的資源,放入特定名稱的文件夾中。比如,表示簡(jiǎn)體中文字符信息的資源,可以放到values-zh-rCN中去,當(dāng)系統(tǒng)語(yǔ)言環(huán)境為簡(jiǎn)體中文時(shí),就會(huì)呈現(xiàn)出中文的字符信息。在Android中,很多相關(guān)配置項(xiàng),都可以按照這樣的方式參與到資源自適應(yīng)的活動(dòng)中來(lái),包括屏幕大小,屏幕朝向,屏幕分辨率,語(yǔ)言環(huán)境,觸屏類型,SDK版本等等。系統(tǒng)會(huì)給所有配置項(xiàng)一個(gè)優(yōu)先級(jí)(或者說(shuō)權(quán)重,次序之類的),當(dāng)用戶提供了多份資源的時(shí)候,系統(tǒng)會(huì)根據(jù)優(yōu)先級(jí)從高到底淘汰備選資源,如果淘汰僅剩了一個(gè),那就是最符合當(dāng)前系統(tǒng)軟硬件語(yǔ)言環(huán)境的資源項(xiàng),如果一個(gè)不剩,擇啟用默認(rèn)項(xiàng)(最是形如values這樣沒(méi)有任何尾巴目錄中的資源。..)。因此,默認(rèn)的資源是非常重要的,它必須是其他所有可選資源項(xiàng)的超集,否則在資源選擇失敗的情況下,應(yīng)用會(huì)凄涼的崩潰。

  關(guān)于資源配置,以及選擇的詳情,參見(jiàn)SDK中的:guide/topics/resources/resources-i18n.html部分。

  作為一枚coder,做界面,很多時(shí)候都是一場(chǎng)夢(mèng)魘。很多時(shí)候,我們會(huì)感覺(jué)對(duì)于底層邏輯實(shí)現(xiàn)的很有把握性,哪怕需求一直在變,也可以通過(guò)不斷的重構(gòu)一直跟進(jìn),一切盡在掌握。但遭遇界面,往往就不再如此,它的好壞總是和審美、體驗(yàn)之類的詞匯扯在一起,在鳳姐芙蓉出沒(méi)的年頭,談審美成為一件恐怖的事情。你可能會(huì)被要求不停的改代碼,就為了移動(dòng)一個(gè)像素,調(diào)整一枚按鈕,瑣碎而無(wú)聊。

  為了改變這樣的狀況,挽救coder們于水生活熱之中,很多開(kāi)發(fā)平臺(tái),都采用了類似于資源文件的解決方案。此類方案的基本思想是,將界面的實(shí)現(xiàn)與底層邏輯的實(shí)現(xiàn)完全剝離開(kāi)來(lái),用資源文件這樣的東西來(lái)描述界面。資源文件的描述語(yǔ)言,往往是結(jié)構(gòu)化很強(qiáng),比如Html,Xml(及其變形體)之類的。于開(kāi)發(fā)語(yǔ)言相比,此類語(yǔ)言邏輯性較弱但結(jié)構(gòu)更好可讀性更強(qiáng)更容易理解,并對(duì)自動(dòng)化工具非常友好,可以于界面的拖拽配置結(jié)合的更加完美。這樣的剝離,可以是的底層邏輯和上層界面獨(dú)立變化,甚至不同的人員開(kāi)發(fā)(這一點(diǎn)在web開(kāi)發(fā)上表現(xiàn)的應(yīng)該很明顯。..),兩者之間的耦合性非常的小,coder們的負(fù)擔(dān),陡然減少(好吧,一個(gè)很挫的資源架構(gòu)也會(huì)額外增加開(kāi)發(fā)人員的負(fù)擔(dān),Symbian同學(xué),請(qǐng)不要對(duì)號(hào)入座。..)。

  結(jié)構(gòu)和格式

  Android的資源文件,是由目錄結(jié)構(gòu),Xml格式的文件,和純數(shù)據(jù)文件構(gòu)成。從格式上來(lái)看,無(wú)疑,學(xué)習(xí)門檻非常低。Xml作為coder們的瑞士軍刀,哪怕使不習(xí)慣,弄得清楚并會(huì)用至少是沒(méi)有問(wèn)題。從配套的工具來(lái)看,Android的ADT,提供了一套可視化的配置工具,說(shuō)不上特別好用,但至少是差強(qiáng)人意能湊合著用,比不上iPhone的,調(diào)戲Symbian還是沒(méi)有問(wèn)題的[強(qiáng)檔廣告首播:有道詞典 for iPhone新版火熱上線,增加了超強(qiáng)單詞本功能,特有的觸電式顫抖單詞切換功能,讓你欲罷不能,持有相關(guān)設(shè)備的童鞋不要猶豫,一擁而上吧。..]。

  Android的資源文件,覆蓋面超級(jí)廣,只要是和界面相關(guān)的,都可以用資源文件表示,比如:UI的樣式,菜單,配置文件,各種描述性字符串,圖片,音頻視頻文件,動(dòng)畫(huà),顏色,尺寸,風(fēng)格和樣式,等等等。所有的資源文件(不考慮asset,它和討論暫無(wú)關(guān)聯(lián)。..),都放在res目錄下,不同類別的資源,需要放置在不同的特定名稱的子文件夾中,或者是寫(xiě)在特定文件名的文件中(或者ms不是必須的,但,不用在這里特立獨(dú)行,尋章辦事也挺好。..)。比如,所有作為UI背景之類的圖片,都需要扔在drawable這類的文件夾中,所有字符串相關(guān)的,都會(huì)放到values目錄下形如strings.xml這樣的文件中(如下圖所示,是一個(gè)資源文件目錄結(jié)構(gòu)的截圖。..)。

  

  每個(gè)xml文件,都有一定的約定。比如一個(gè)字符串,會(huì)放在《string》《/string》這樣的xml element中(如下圖所示。..),你可以通過(guò)eclipse的ADT插件提供的可是界面去填而不關(guān)注具體規(guī)范,也可以直接人肉打造,前者對(duì)于新手來(lái)說(shuō)更為直觀,后者對(duì)于老鳥(niǎo)而言更為迅捷。

  

  可配置性

  程序邏輯總是不變應(yīng)萬(wàn)變的,但界面往往是需要能夠72變。首先一種變化因素,就是狀態(tài)。想象一下,我們往往會(huì)有這樣類似的需求,一個(gè)按鈕,我們需要沒(méi)有按下去的時(shí)候是一種背景,按的過(guò)程中刷的變成另一副模樣,當(dāng)它可用的時(shí)候需要鮮鮮亮的一個(gè)樣子,不可用的時(shí)候最好是灰不溜秋沒(méi)人愿點(diǎn)的慫樣,諸如此類。傳統(tǒng)編程模型下(Symbian,哥叫你出來(lái)當(dāng)模特。..),我們總是需要不厭其煩的用代碼控制這樣的事情。監(jiān)聽(tīng)不同的事件,見(jiàn)縫插針的切換背景,并祈禱上天,千萬(wàn)別讓哥調(diào)整,否則哥和你沒(méi)完。

  

  在Android中,做這個(gè)事情,變得簡(jiǎn)單許多,通過(guò)預(yù)設(shè)的一些Xml屬性,能夠輕松的搞定。如上圖所示,是Radio Button的背景。通過(guò)搭配不同的屬性,就可以自動(dòng)轉(zhuǎn)換背景。比如第一個(gè)《item》,說(shuō)的是當(dāng)Radio Button被選中,并且具有焦點(diǎn)的時(shí)候,顯示btn_radio_on這幅圖片,而最后一個(gè)《item》,說(shuō)的是前述條件都不滿足,并且處于選中狀態(tài),那么顯示btn_radio_on這幅圖片。

  另外一個(gè)更易變的因素,就是手機(jī)硬件/軟件環(huán)境了,畢竟,不是家家都是蘋(píng)果,一個(gè)平臺(tái)搭一款手機(jī),手機(jī)款形多樣化,幾乎是避免不了的問(wèn)題。沒(méi)有人希望自己做的軟件在大屏幕手機(jī)上閃亮光鮮,換個(gè)小屏幕就慘不忍睹,豎屏看像那么回事橫屏看就擠做一團(tuán)。還有就是語(yǔ)言環(huán)境了,做為一個(gè)有國(guó)際眼光的coder,作面向世界的NB軟件是咱的夢(mèng)想,但我們不能因?yàn)樽约旱膲?mèng)想逼迫大家都去學(xué)中文,做一款軟件可以根據(jù)手機(jī)的語(yǔ)言環(huán)境選擇最合適展示的語(yǔ)言,很多時(shí)候,是一個(gè)需要具備的功能點(diǎn)。

  在Android中,實(shí)現(xiàn)這些,都是舉手之勞。方法就是將和環(huán)境相關(guān)的資源,放入特定名稱的文件夾中。比如,表示簡(jiǎn)體中文字符信息的資源,可以放到values-zh-rCN中去,當(dāng)系統(tǒng)語(yǔ)言環(huán)境為簡(jiǎn)體中文時(shí),就會(huì)呈現(xiàn)出中文的字符信息。在Android中,很多相關(guān)配置項(xiàng),都可以按照這樣的方式參與到資源自適應(yīng)的活動(dòng)中來(lái),包括屏幕大小,屏幕朝向,屏幕分辨率,語(yǔ)言環(huán)境,觸屏類型,SDK版本等等。系統(tǒng)會(huì)給所有配置項(xiàng)一個(gè)優(yōu)先級(jí)(或者說(shuō)權(quán)重,次序之類的),當(dāng)用戶提供了多份資源的時(shí)候,系統(tǒng)會(huì)根據(jù)優(yōu)先級(jí)從高到底淘汰備選資源,如果淘汰僅剩了一個(gè),那就是最符合當(dāng)前系統(tǒng)軟硬件語(yǔ)言環(huán)境的資源項(xiàng),如果一個(gè)不剩,擇啟用默認(rèn)項(xiàng)(最是形如values這樣沒(méi)有任何尾巴目錄中的資源。..)。因此,默認(rèn)的資源是非常重要的,它必須是其他所有可選資源項(xiàng)的超集,否則在資源選擇失敗的情況下,應(yīng)用會(huì)凄涼的崩潰。

  關(guān)于資源配置,以及選擇的詳情,參見(jiàn)SDK中的:guide/topics/resources/resources-i18n.html部分。

  R類

  在使用資源后,界面邏輯與底層邏輯的耦合被降低了,但這不意味著,兩者沒(méi)有關(guān)聯(lián)了。比如,需要為某個(gè)按鈕增加一個(gè)點(diǎn)擊事件,就需要定位到所需的那個(gè)按鈕;再比如,你需要使用某個(gè)字符串資源,通知用戶某件事情,就需要能定位到資源中放置的該字串。

  最顯而易見(jiàn)的一種方式,就是通過(guò)字符串比較,用名字信息在資源的xml描述文件中定位到所需的內(nèi)容,加載并使用。這種方式,解決了查找的問(wèn)題,但反復(fù)的字符串比較,勢(shì)必帶來(lái)嚴(yán)重的效率隱患。因此,在Android中,類似于Symbian的方法,引入了一個(gè)R類。

  它的基本思想是,通過(guò)增加一個(gè)額外的編譯器,為所有的資源項(xiàng),都賦予一個(gè)32位的整形數(shù)來(lái)表示,同一個(gè)資源像的不同配置,都使用同一個(gè)id。這個(gè)整形數(shù),就相當(dāng)于這個(gè)資源項(xiàng)的門牌號(hào)碼,能夠幫助定位到對(duì)應(yīng)的資源項(xiàng)。所有的這些整形數(shù),都以常量的方式,整合到一個(gè)Java類中,這個(gè)類就是R類。這樣,在程序中,就可以通過(guò)使用這個(gè)R類,來(lái)查找所需的資源,這就將字符串比較,簡(jiǎn)化成了一個(gè)整形數(shù)的比較,大大的節(jié)約了開(kāi)銷。

  不得不說(shuō),這整套邏輯和Symbian中的資源文件預(yù)編譯一致。但兩者很不同的點(diǎn)在于Symbian中的整形數(shù),代表的是一個(gè)二進(jìn)制流的偏移量,資源中的內(nèi)容在編譯時(shí)決定了。而Android中的整形數(shù),是一個(gè)有邏輯意義的數(shù)值,它表達(dá)了這個(gè)資源所處的資源包,類別,和腳標(biāo),它的具體內(nèi)容在運(yùn)行時(shí)才確定,這使得它的靈活性大大增強(qiáng),付出的則是一定的效率代價(jià)。

  實(shí)現(xiàn)

  按照慣例,還是要說(shuō)實(shí)現(xiàn)的,以一個(gè)查找流程為示例。當(dāng)在Activity中需要使用字符串的,會(huì)調(diào)用它的getString方法,傳入R.stirng.xxx的一個(gè)整形數(shù),換取一個(gè)符合當(dāng)前機(jī)器環(huán)境配置的字符串。

  getString,追根溯源,來(lái)到AssetManager類中。Asset類,其實(shí)是一個(gè)空殼,它僅僅是提供了一些便利的接口,而將請(qǐng)求,通過(guò)JNI的接口,傳入到了底層C++實(shí)現(xiàn)的類庫(kù)中。

  在底層的實(shí)現(xiàn),主要是在C++實(shí)現(xiàn)的,AssetManager,ResourceTypes等等之中。其中:

  JNI文件在:framework/base/core/jni

  頭文件在:framework/base/include/utils

  CPP文件在:framework/base/libs/utils

  具體實(shí)現(xiàn),和前述的算法邏輯是一致的。每一個(gè)資源的id,32位,高8位表示資源包,低16位用于描述腳標(biāo),中間8位,用來(lái)說(shuō)明類別。所有資源中的文件,都被預(yù)處理了,放入到了一系列的隊(duì)列和表中,通過(guò)id,可以查到具體的位置。然后根據(jù)緩存的環(huán)境設(shè)置對(duì)象,跑一次淘汰算法,獲得匹配的資源對(duì)象的對(duì)應(yīng)文件和偏移量。然后將值讀取出來(lái),通過(guò)JNI接口,拷貝回去。

  以上這些描述,并不能幫助了解真實(shí)的實(shí)現(xiàn)細(xì)節(jié),主要是為了促使大家對(duì)讀取資源的效率有一個(gè)比較直觀的認(rèn)知。整個(gè)資源讀取的流程比較長(zhǎng),但是實(shí)現(xiàn)在C++中,可以預(yù)想,效率比Java高一些,開(kāi)發(fā)人員,應(yīng)該能夠根據(jù)自己的需求,決定是否將內(nèi)容寫(xiě)入資源文件中(還是寫(xiě)在代碼中。..),是不是需要自己稍微緩存一下,諸如此類。

此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權(quán)禁止轉(zhuǎn)載。