作為一枚coder,,做界面,,很多時候都是一場夢魘。很多時候,,我們會感覺對于底層邏輯實現(xiàn)的很有把握性,,哪怕需求一直在變,也可以通過不斷的重構(gòu)一直跟進(jìn),,一切盡在掌握,。但遭遇界面,往往就不再如此,,它的好壞總是和審美,、體驗之類的詞匯扯在一起,在鳳姐芙蓉出沒的年頭,,談審美成為一件恐怖的事情,。你可能會被要求不停的改代碼,就為了移動一個像素,,調(diào)整一枚按鈕,,瑣碎而無聊。
為了改變這樣的狀況,,挽救coder們于水生活熱之中,,很多開發(fā)平臺,都采用了類似于資源文件的解決方案,。此類方案的基本思想是,,將界面的實現(xiàn)與底層邏輯的實現(xiàn)完全剝離開來,用資源文件這樣的東西來描述界面,。資源文件的描述語言,,往往是結(jié)構(gòu)化很強(qiáng),比如Html,,Xml(及其變形體)之類的,。于開發(fā)語言相比,此類語言邏輯性較弱但結(jié)構(gòu)更好可讀性更強(qiáng)更容易理解,,并對自動化工具非常友好,,可以于界面的拖拽配置結(jié)合的更加完美。這樣的剝離,,可以是的底層邏輯和上層界面獨立變化,,甚至不同的人員開發(fā)(這一點在web開發(fā)上表現(xiàn)的應(yīng)該很明顯。..),,兩者之間的耦合性非常的小,,coder們的負(fù)擔(dān),,陡然減少(好吧,一個很挫的資源架構(gòu)也會額外增加開發(fā)人員的負(fù)擔(dān),,Symbian同學(xué),,請不要對號入座。..),。
結(jié)構(gòu)和格式
Android的資源文件,,是由目錄結(jié)構(gòu),Xml格式的文件,,和純數(shù)據(jù)文件構(gòu)成,。從格式上來看,無疑,,學(xué)習(xí)門檻非常低,。Xml作為coder們的瑞士軍刀,哪怕使不習(xí)慣,,弄得清楚并會用至少是沒有問題,。從配套的工具來看,Android的ADT,,提供了一套可視化的配置工具,,說不上特別好用,但至少是差強(qiáng)人意能湊合著用,,比不上iPhone的,,調(diào)戲Symbian還是沒有問題的[強(qiáng)檔廣告首播:有道詞典 for iPhone新版火熱上線,增加了超強(qiáng)單詞本功能,,特有的觸電式顫抖單詞切換功能,,讓你欲罷不能,持有相關(guān)設(shè)備的童鞋不要猶豫,,一擁而上吧,。..]。
Android的資源文件,,覆蓋面超級廣,,只要是和界面相關(guān)的,都可以用資源文件表示,,比如:UI的樣式,,菜單,配置文件,,各種描述性字符串,,圖片,音頻視頻文件,動畫,,顏色,,尺寸,,風(fēng)格和樣式,,等等等。所有的資源文件(不考慮asset,,它和討論暫無關(guān)聯(lián),。..),都放在res目錄下,,不同類別的資源,,需要放置在不同的特定名稱的子文件夾中,或者是寫在特定文件名的文件中(或者ms不是必須的,,但,,不用在這里特立獨行,尋章辦事也挺好,。..),。比如,所有作為UI背景之類的圖片,,都需要扔在drawable這類的文件夾中,,所有字符串相關(guān)的,都會放到values目錄下形如strings.xml這樣的文件中(如下圖所示,,是一個資源文件目錄結(jié)構(gòu)的截圖,。..)。
每個xml文件,,都有一定的約定,。比如一個字符串,會放在《string》《/string》這樣的xml element中(如下圖所示,。..),,你可以通過eclipse的ADT插件提供的可是界面去填而不關(guān)注具體規(guī)范,也可以直接人肉打造,,前者對于新手來說更為直觀,,后者對于老鳥而言更為迅捷。
可配置性
程序邏輯總是不變應(yīng)萬變的,,但界面往往是需要能夠72變,。首先一種變化因素,就是狀態(tài),。想象一下,,我們往往會有這樣類似的需求,一個按鈕,我們需要沒有按下去的時候是一種背景,,按的過程中刷的變成另一副模樣,,當(dāng)它可用的時候需要鮮鮮亮的一個樣子,不可用的時候最好是灰不溜秋沒人愿點的慫樣,,諸如此類,。傳統(tǒng)編程模型下(Symbian,哥叫你出來當(dāng)模特,。..),,我們總是需要不厭其煩的用代碼控制這樣的事情。監(jiān)聽不同的事件,,見縫插針的切換背景,,并祈禱上天,千萬別讓哥調(diào)整,,否則哥和你沒完,。
在Android中,,做這個事情,,變得簡單許多,通過預(yù)設(shè)的一些Xml屬性,,能夠輕松的搞定,。如上圖所示,,是Radio Button的背景。通過搭配不同的屬性,,就可以自動轉(zhuǎn)換背景,。比如第一個《item》,說的是當(dāng)Radio Button被選中,,并且具有焦點的時候,,顯示btn_radio_on這幅圖片,而最后一個《item》,,說的是前述條件都不滿足,,并且處于選中狀態(tài),那么顯示btn_radio_on這幅圖片,。
另外一個更易變的因素,,就是手機(jī)硬件/軟件環(huán)境了,畢竟,,不是家家都是蘋果,,一個平臺搭一款手機(jī),手機(jī)款形多樣化,,幾乎是避免不了的問題,。沒有人希望自己做的軟件在大屏幕手機(jī)上閃亮光鮮,換個小屏幕就慘不忍睹,豎屏看像那么回事橫屏看就擠做一團(tuán),。還有就是語言環(huán)境了,,做為一個有國際眼光的coder,作面向世界的NB軟件是咱的夢想,,但我們不能因為自己的夢想逼迫大家都去學(xué)中文,,做一款軟件可以根據(jù)手機(jī)的語言環(huán)境選擇最合適展示的語言,很多時候,,是一個需要具備的功能點,。
在Android中,,實現(xiàn)這些,,都是舉手之勞。方法就是將和環(huán)境相關(guān)的資源,,放入特定名稱的文件夾中,。比如,表示簡體中文字符信息的資源,,可以放到values-zh-rCN中去,,當(dāng)系統(tǒng)語言環(huán)境為簡體中文時,就會呈現(xiàn)出中文的字符信息,。在Android中,,很多相關(guān)配置項,都可以按照這樣的方式參與到資源自適應(yīng)的活動中來,,包括屏幕大小,,屏幕朝向,屏幕分辨率,,語言環(huán)境,,觸屏類型,SDK版本等等,。系統(tǒng)會給所有配置項一個優(yōu)先級(或者說權(quán)重,,次序之類的),當(dāng)用戶提供了多份資源的時候,,系統(tǒng)會根據(jù)優(yōu)先級從高到底淘汰備選資源,,如果淘汰僅剩了一個,那就是最符合當(dāng)前系統(tǒng)軟硬件語言環(huán)境的資源項,,如果一個不剩,,擇啟用默認(rèn)項(最是形如values這樣沒有任何尾巴目錄中的資源。..),。因此,,默認(rèn)的資源是非常重要的,它必須是其他所有可選資源項的超集,否則在資源選擇失敗的情況下,,應(yīng)用會凄涼的崩潰,。
關(guān)于資源配置,以及選擇的詳情,,參見SDK中的:guide/topics/resources/resources-i18n.html部分,。
作為一枚coder,做界面,,很多時候都是一場夢魘,。很多時候,我們會感覺對于底層邏輯實現(xiàn)的很有把握性,,哪怕需求一直在變,,也可以通過不斷的重構(gòu)一直跟進(jìn),一切盡在掌握,。但遭遇界面,,往往就不再如此,它的好壞總是和審美,、體驗之類的詞匯扯在一起,,在鳳姐芙蓉出沒的年頭,談審美成為一件恐怖的事情,。你可能會被要求不停的改代碼,,就為了移動一個像素,調(diào)整一枚按鈕,,瑣碎而無聊,。
為了改變這樣的狀況,挽救coder們于水生活熱之中,,很多開發(fā)平臺,,都采用了類似于資源文件的解決方案。此類方案的基本思想是,,將界面的實現(xiàn)與底層邏輯的實現(xiàn)完全剝離開來,,用資源文件這樣的東西來描述界面。資源文件的描述語言,,往往是結(jié)構(gòu)化很強(qiáng),,比如Html,Xml(及其變形體)之類的,。于開發(fā)語言相比,,此類語言邏輯性較弱但結(jié)構(gòu)更好可讀性更強(qiáng)更容易理解,并對自動化工具非常友好,,可以于界面的拖拽配置結(jié)合的更加完美,。這樣的剝離,,可以是的底層邏輯和上層界面獨立變化,甚至不同的人員開發(fā)(這一點在web開發(fā)上表現(xiàn)的應(yīng)該很明顯,。..),,兩者之間的耦合性非常的小,coder們的負(fù)擔(dān),,陡然減少(好吧,,一個很挫的資源架構(gòu)也會額外增加開發(fā)人員的負(fù)擔(dān),Symbian同學(xué),,請不要對號入座,。..)。
結(jié)構(gòu)和格式
Android的資源文件,,是由目錄結(jié)構(gòu),,Xml格式的文件,和純數(shù)據(jù)文件構(gòu)成,。從格式上來看,,無疑,學(xué)習(xí)門檻非常低,。Xml作為coder們的瑞士軍刀,哪怕使不習(xí)慣,,弄得清楚并會用至少是沒有問題,。從配套的工具來看,Android的ADT,,提供了一套可視化的配置工具,,說不上特別好用,但至少是差強(qiáng)人意能湊合著用,,比不上iPhone的,,調(diào)戲Symbian還是沒有問題的[強(qiáng)檔廣告首播:有道詞典 for iPhone新版火熱上線,增加了超強(qiáng)單詞本功能,,特有的觸電式顫抖單詞切換功能,,讓你欲罷不能,持有相關(guān)設(shè)備的童鞋不要猶豫,,一擁而上吧,。..]。
Android的資源文件,,覆蓋面超級廣,,只要是和界面相關(guān)的,都可以用資源文件表示,,比如:UI的樣式,,菜單,,配置文件,各種描述性字符串,,圖片,,音頻視頻文件,動畫,,顏色,,尺寸,風(fēng)格和樣式,,等等等,。所有的資源文件(不考慮asset,它和討論暫無關(guān)聯(lián),。..),,都放在res目錄下,不同類別的資源,,需要放置在不同的特定名稱的子文件夾中,,或者是寫在特定文件名的文件中(或者ms不是必須的,但,,不用在這里特立獨行,,尋章辦事也挺好。..),。比如,,所有作為UI背景之類的圖片,都需要扔在drawable這類的文件夾中,,所有字符串相關(guān)的,,都會放到values目錄下形如strings.xml這樣的文件中(如下圖所示,是一個資源文件目錄結(jié)構(gòu)的截圖,。..),。
每個xml文件,都有一定的約定,。比如一個字符串,,會放在《string》《/string》這樣的xml element中(如下圖所示。..),,你可以通過eclipse的ADT插件提供的可是界面去填而不關(guān)注具體規(guī)范,,也可以直接人肉打造,前者對于新手來說更為直觀,,后者對于老鳥而言更為迅捷,。
可配置性
程序邏輯總是不變應(yīng)萬變的,但界面往往是需要能夠72變,。首先一種變化因素,,就是狀態(tài),。想象一下,我們往往會有這樣類似的需求,,一個按鈕,,我們需要沒有按下去的時候是一種背景,按的過程中刷的變成另一副模樣,,當(dāng)它可用的時候需要鮮鮮亮的一個樣子,,不可用的時候最好是灰不溜秋沒人愿點的慫樣,諸如此類,。傳統(tǒng)編程模型下(Symbian,,哥叫你出來當(dāng)模特。..),,我們總是需要不厭其煩的用代碼控制這樣的事情,。監(jiān)聽不同的事件,見縫插針的切換背景,,并祈禱上天,,千萬別讓哥調(diào)整,否則哥和你沒完,。
在Android中,,做這個事情,變得簡單許多,,通過預(yù)設(shè)的一些Xml屬性,,能夠輕松的搞定。如上圖所示,,是Radio Button的背景。通過搭配不同的屬性,,就可以自動轉(zhuǎn)換背景,。比如第一個《item》,說的是當(dāng)Radio Button被選中,,并且具有焦點的時候,,顯示btn_radio_on這幅圖片,而最后一個《item》,,說的是前述條件都不滿足,,并且處于選中狀態(tài),那么顯示btn_radio_on這幅圖片,。
另外一個更易變的因素,,就是手機(jī)硬件/軟件環(huán)境了,畢竟,,不是家家都是蘋果,,一個平臺搭一款手機(jī),,手機(jī)款形多樣化,幾乎是避免不了的問題,。沒有人希望自己做的軟件在大屏幕手機(jī)上閃亮光鮮,,換個小屏幕就慘不忍睹,豎屏看像那么回事橫屏看就擠做一團(tuán),。還有就是語言環(huán)境了,,做為一個有國際眼光的coder,作面向世界的NB軟件是咱的夢想,,但我們不能因為自己的夢想逼迫大家都去學(xué)中文,,做一款軟件可以根據(jù)手機(jī)的語言環(huán)境選擇最合適展示的語言,很多時候,,是一個需要具備的功能點,。
在Android中,實現(xiàn)這些,,都是舉手之勞,。方法就是將和環(huán)境相關(guān)的資源,放入特定名稱的文件夾中,。比如,,表示簡體中文字符信息的資源,可以放到values-zh-rCN中去,,當(dāng)系統(tǒng)語言環(huán)境為簡體中文時,,就會呈現(xiàn)出中文的字符信息。在Android中,,很多相關(guān)配置項,,都可以按照這樣的方式參與到資源自適應(yīng)的活動中來,包括屏幕大小,,屏幕朝向,,屏幕分辨率,語言環(huán)境,,觸屏類型,,SDK版本等等。系統(tǒng)會給所有配置項一個優(yōu)先級(或者說權(quán)重,,次序之類的),,當(dāng)用戶提供了多份資源的時候,系統(tǒng)會根據(jù)優(yōu)先級從高到底淘汰備選資源,,如果淘汰僅剩了一個,,那就是最符合當(dāng)前系統(tǒng)軟硬件語言環(huán)境的資源項,如果一個不剩,,擇啟用默認(rèn)項(最是形如values這樣沒有任何尾巴目錄中的資源,。..),。因此,默認(rèn)的資源是非常重要的,,它必須是其他所有可選資源項的超集,,否則在資源選擇失敗的情況下,應(yīng)用會凄涼的崩潰,。
關(guān)于資源配置,,以及選擇的詳情,參見SDK中的:guide/topics/resources/resources-i18n.html部分,。
R類
在使用資源后,,界面邏輯與底層邏輯的耦合被降低了,但這不意味著,,兩者沒有關(guān)聯(lián)了,。比如,需要為某個按鈕增加一個點擊事件,,就需要定位到所需的那個按鈕,;再比如,你需要使用某個字符串資源,,通知用戶某件事情,,就需要能定位到資源中放置的該字串。
最顯而易見的一種方式,,就是通過字符串比較,,用名字信息在資源的xml描述文件中定位到所需的內(nèi)容,加載并使用,。這種方式,,解決了查找的問題,但反復(fù)的字符串比較,,勢必帶來嚴(yán)重的效率隱患,。因此,在Android中,,類似于Symbian的方法,引入了一個R類,。
它的基本思想是,,通過增加一個額外的編譯器,為所有的資源項,,都賦予一個32位的整形數(shù)來表示,,同一個資源像的不同配置,都使用同一個id,。這個整形數(shù),,就相當(dāng)于這個資源項的門牌號碼,,能夠幫助定位到對應(yīng)的資源項。所有的這些整形數(shù),,都以常量的方式,,整合到一個Java類中,這個類就是R類,。這樣,,在程序中,就可以通過使用這個R類,,來查找所需的資源,,這就將字符串比較,簡化成了一個整形數(shù)的比較,,大大的節(jié)約了開銷,。
不得不說,這整套邏輯和Symbian中的資源文件預(yù)編譯一致,。但兩者很不同的點在于Symbian中的整形數(shù),,代表的是一個二進(jìn)制流的偏移量,資源中的內(nèi)容在編譯時決定了,。而Android中的整形數(shù),,是一個有邏輯意義的數(shù)值,它表達(dá)了這個資源所處的資源包,,類別,,和腳標(biāo),它的具體內(nèi)容在運(yùn)行時才確定,,這使得它的靈活性大大增強(qiáng),,付出的則是一定的效率代價。
實現(xiàn)
按照慣例,,還是要說實現(xiàn)的,,以一個查找流程為示例。當(dāng)在Activity中需要使用字符串的,,會調(diào)用它的getString方法,,傳入R.stirng.xxx的一個整形數(shù),換取一個符合當(dāng)前機(jī)器環(huán)境配置的字符串,。
getString,,追根溯源,來到AssetManager類中,。Asset類,,其實是一個空殼,它僅僅是提供了一些便利的接口,而將請求,,通過JNI的接口,,傳入到了底層C++實現(xiàn)的類庫中。
在底層的實現(xiàn),,主要是在C++實現(xiàn)的,,AssetManager,ResourceTypes等等之中,。其中:
JNI文件在:framework/base/core/jni
頭文件在:framework/base/include/utils
CPP文件在:framework/base/libs/utils
具體實現(xiàn),,和前述的算法邏輯是一致的。每一個資源的id,,32位,,高8位表示資源包,低16位用于描述腳標(biāo),,中間8位,,用來說明類別。所有資源中的文件,,都被預(yù)處理了,,放入到了一系列的隊列和表中,通過id,,可以查到具體的位置,。然后根據(jù)緩存的環(huán)境設(shè)置對象,跑一次淘汰算法,,獲得匹配的資源對象的對應(yīng)文件和偏移量,。然后將值讀取出來,通過JNI接口,,拷貝回去,。
以上這些描述,并不能幫助了解真實的實現(xiàn)細(xì)節(jié),,主要是為了促使大家對讀取資源的效率有一個比較直觀的認(rèn)知,。整個資源讀取的流程比較長,但是實現(xiàn)在C++中,,可以預(yù)想,,效率比Java高一些,開發(fā)人員,,應(yīng)該能夠根據(jù)自己的需求,,決定是否將內(nèi)容寫入資源文件中(還是寫在代碼中。..),,是不是需要自己稍微緩存一下,諸如此類。