欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android?資源加載使用偽代碼示例分析

 更新時(shí)間:2022年10月12日 09:36:51   作者:Petterp  
這篇文章主要為大家介紹了Android?資源加載使用偽代碼示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

聊到 Android 的 資源加載 ,每一個(gè)開(kāi)發(fā)同學(xué)都會(huì)非常熟悉,畢竟從使用來(lái)說(shuō),我們?nèi)粘6紩?huì)見(jiàn)到,比如 getText() 等等。

那如果此時(shí)問(wèn)你,你知道 它們到底是怎么被加載的,內(nèi)部會(huì)有什么處理嗎?

為什么同一個(gè)drawable界面更改了透明度,其他界面也會(huì)生效?

如果你對(duì)上述問(wèn)題依然存疑,那本文可能會(huì)對(duì)你有所幫助。

介于此,本篇將由淺入深,從源頭理清 Resource.getx() 的那些事,從而為理解 Android資源加載 邁出第一步。故此名: 小試牛刀。

本篇定位中等??,主要通過(guò)偽源碼分析的形式,從而探索應(yīng)用層 Resource.getx 的實(shí)現(xiàn)細(xì)節(jié)。

Resource是什么?

Resource,在 Android 中,指的是我們開(kāi)發(fā)中使用到的資源,例如 drawableString、anim、color 等。其會(huì)在開(kāi)發(fā)階段生成相應(yīng)的R類(lèi)以及對(duì)應(yīng)的 資源ID ,以便開(kāi)發(fā)者在使用時(shí)通過(guò)傳遞 資源Id ,從而獲取相應(yīng)類(lèi)型的資源文件。

比如我們?cè)?Activity,Fragment 中經(jīng)常使用的 getString() , getDrawable() ,內(nèi)部也都是調(diào)用的 resource.getxx 實(shí)現(xiàn)。

常見(jiàn)也有 ContextCompat.getDrawable() ,那它與直接調(diào)用resource.getDrawable()有什么區(qū)別?

見(jiàn)名知意,其主要是作為兼容使用,目的是解決不同版本之間的差異。

基礎(chǔ)概念

TypedValue

用于保存數(shù)據(jù)的動(dòng)態(tài)容器,主要用于配合 Resource 保存資源。

具體而言,當(dāng)我們獲取資源時(shí),底層會(huì)調(diào)用相應(yīng)的原生方法將讀取到的資源信息寫(xiě)入其中,以便后續(xù)的判斷與使用;

AssetsManager

資源管理器,用于讀取打包到 Apk 內(nèi)部的資源文件。

具體而言,當(dāng)我們調(diào)用 getxxx 時(shí),其最終會(huì)去調(diào)用相應(yīng)的原生方法獲取資源信息并寫(xiě)入 TypedValue ;

ResourcesImpl

Resource 的具體實(shí)現(xiàn)類(lèi),我們調(diào)用的相關(guān) getxxx 方法,最終都是其作為具體實(shí)現(xiàn),內(nèi)部最終會(huì)調(diào)用 AssetsManager 進(jìn)行加載資源,并且會(huì)處理與之關(guān)聯(lián)的所有緩存。

getText

getText(R.string.xx)

用于從資源文件中獲取文本,具體源碼如下:

從源碼中看,我們調(diào)用的 getText() 最終實(shí)際調(diào)用了 ResourcesImpl , 內(nèi)部會(huì)使用 AssetsManager 去從底層獲取相應(yīng)的文本資源,并將其保存到 TypedValue 中。如果此次獲取的文本資源是字符串類(lèi)型,則直接從字符串常量池中去取,否則將取到的文本資源轉(zhuǎn)為字符串后返回。

getDrawable

getDrawable(R.drawable.xxx)

用于從資源文件中獲取可繪制對(duì)象,具體偽源碼如下:

當(dāng)我們調(diào)用 getDrawable() 時(shí),內(nèi)部先會(huì)通過(guò) getValueForDensity() 獲取當(dāng)前密度下相應(yīng)的資源文件,并將其寫(xiě)入到 TypeValue 中;

如果不存在資源文件,則直接拋出異常。然后通過(guò) ResourcesImpl.loadDrawable 去加載 Drawable。

繼續(xù)沿著剛才的源碼,我們?nèi)タ纯?loadDrawable 內(nèi)部到底做了什么,偽代碼如下:

這個(gè)方法流程較長(zhǎng),我們將其分為下面幾個(gè)步驟:

  • 判斷當(dāng)前要加載的 drawable 是否具有緩存;
  • 判斷當(dāng)前 drawable 是否為顏色drawable;
  • 如果當(dāng)前沒(méi)有加載 drawable &&當(dāng)前drawable 已緩存 ,直接返回該drawable;
  • 從當(dāng)前緩存中取出當(dāng)前 drawable 對(duì)應(yīng)的 狀態(tài)與數(shù)據(jù)參數(shù)(如果存在緩存) ;

創(chuàng)建新的 drawable 。如果當(dāng)前存在緩存,則利用緩存的狀態(tài)(Drawable.ConstantState) 構(gòu)建 Drawable,否則如果是顏色drawable,則直接創(chuàng)建;否則調(diào)用 從xml或者資源中加載drawable,具體偽代碼如下圖:

  • 處理構(gòu)建的drawable 主題與參數(shù) ;
  • 如果當(dāng)前drawable 沒(méi)有緩存 ,則將添加到緩存中。

小結(jié)

當(dāng)我們調(diào)用 getDrawable() 時(shí),內(nèi)部會(huì)先判斷當(dāng)前資源是否存在,如果不存在則直接拋出異常;接著調(diào)用 ResourcesImpl.loadDrawable 去加載具體的 drawable ,內(nèi)部會(huì)根據(jù)要加載的 drawable類(lèi)型、是否是Color,以及是否存在緩存綜合獲取,如果存在當(dāng)前屏幕密度的drawable,則使用緩存,否則重新加載。然后根據(jù)要加載的 drawable 文件后綴 決定是 colorDrawable 還是 BitMapDrawable ,或者是其他類(lèi)型的Drawable,最后將加載完成的 Drawable狀態(tài)與配置參數(shù)(ConstantState) 加入到 緩存 中。

Tips

知道了 Drawable 會(huì)被緩存的知識(shí)點(diǎn),此時(shí)就不難解釋為什么開(kāi)發(fā)中會(huì)遇到同一個(gè) Drawable 更改了透明度,其他界面用到這個(gè) Drawable 的地方也會(huì)受到了影響。

如下示例:

解決辦法就是,在 drawable 更改透明度時(shí),調(diào)用 mutate() 即可,原理上也很簡(jiǎn)單,重新new了一個(gè)狀態(tài):

background.mutate().alpha = 100
復(fù)制代碼

例如:

getColor

getColor(R.color.xxx)

用于獲取相應(yīng) 資源id 關(guān)聯(lián)的顏色,具體的源碼如下:

當(dāng)我們調(diào)用 getColor() 時(shí),內(nèi)部先會(huì)通過(guò) getValue() 獲取相應(yīng)的 color 資源,并將其保存到 TypeValue 中;如果不存在資源文件,則直接拋出異常。然后通過(guò) ResourcesImpl.loadColorStateList() 去加載,最后返回顏色狀態(tài)列表的 默認(rèn)顯示顏色。

我們繼續(xù)向下看: loadColorStateList()

當(dāng)調(diào)用 loadColorStateList 加載顏色狀態(tài)合集時(shí),內(nèi)部有兩個(gè)分支:

  • 如果當(dāng)前要獲取的顏色類(lèi)型是 “#xxx” ,則先從預(yù)加載數(shù)組中取,如果此時(shí)沒(méi)有加載,則創(chuàng)新的 ColorStateList ,并將其存到預(yù)加載數(shù)組中;
  • 如果當(dāng)前要獲取的顏色類(lèi)型是引用類(lèi)型,則意味著當(dāng)前可能要從xml中去取。內(nèi)部先從緩存數(shù)組中去,如果不存在則再去預(yù)加載數(shù)組中取,如果依然不存在,則調(diào)用 loadComplexColorForCookie() 重新初始化。當(dāng)加載完成后,如果此時(shí)正在預(yù)加載,將其添加到預(yù)加載數(shù)組中,否則將其添加到緩存里。

接著上面的末梢,我們最后再去看一下 loadComplexColorForCookie() ,也即一個(gè)全新的color到底是如何從xml中拿到

該方法里,先判斷資源文件的后綴名,如果非 .xml 類(lèi)型,則該資源無(wú)法讀取,直接拋出異常;否則先調(diào)用 loadXmlResourceParser() 拿到該資源文件的 xml解析器 ,再由解析器的 name 判斷具體的資源類(lèi)型,從而初始化具體的顏色類(lèi)。

總結(jié)

當(dāng)我們調(diào)用 getColor() 獲取某個(gè)顏色資源時(shí),內(nèi)部會(huì)先通過(guò) AssetsManager 加載該資源,并將其保存到 TypedValue 中,如果沒(méi)有讀到,則拋出異常;否則調(diào)用 ResoucesImpl.loadColorStateList() 獲取顏色資源,如果該資源在緩存中存在,則直接取出并返回新的實(shí)例,否則根據(jù)當(dāng)前要加載的類(lèi)型,如果是 “#xxx” ,則直接初始化并添加到緩存,否則判斷 TypedValue 中保存的資源信息 后綴 是否為 xml ,如果不是則直接拋出異常,證明此時(shí)非 .xml 文件,文件無(wú)法讀取,否則通過(guò) AssetManager 獲取該資源對(duì)應(yīng)的 xml解析器 ,并判斷解析器的名字,從而決定創(chuàng)建 GradientColor 還是 ColorStateList,然后將結(jié)果緩存到 ResourcesImpl 中并返回。

關(guān)于 Resource.getx() 相關(guān)的底層實(shí)現(xiàn)到這里就分析結(jié)束了。本篇中,我們以 Kotlin+[裁枝剪葉] 的方式,提供一個(gè)較清晰的脈絡(luò),以供更好的讀懂應(yīng)用層源碼設(shè)計(jì),關(guān)于更細(xì)節(jié)的原生實(shí)現(xiàn),并不是本篇所關(guān)注的。所謂一眼入森,而不在林,正是如此。

現(xiàn)在讓我們反推上去:

原來(lái)我們每次調(diào)用 getDrawable() 時(shí),內(nèi)部都是做了緩存處理(緩存了ConstantState),原來(lái)我們獲取的 drawable,無(wú)非就三種大的類(lèi)型:

  • .xml 結(jié)尾的,ColorDrawable 或者 非ColorDrawable;
  • 非.xml 結(jié)尾的,即為 BitmapDrawable

那他們又是怎么判斷得出的呢?通過(guò) AssetManager 獲取,將其保存到 TypedValue 中,使用時(shí)通過(guò)判斷 資源文件名后綴 而定。又因?yàn)?code>drawable 存在 緩存狀態(tài)復(fù)用 ,所以又會(huì)導(dǎo)致 一處更新,處處同步 問(wèn)題。原來(lái) getColor() 內(nèi)部同樣做了緩存處理等。

至此,關(guān)于 Android-Resource 的求知篇正式開(kāi)始,下一篇我將同大家分析 Resource 的初始化時(shí)機(jī)以及與 Resource.system() 的區(qū)別。

更多關(guān)于Android 資源加載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android5.0以上實(shí)現(xiàn)全透明的狀態(tài)欄方法(仿網(wǎng)易云界面)

    Android5.0以上實(shí)現(xiàn)全透明的狀態(tài)欄方法(仿網(wǎng)易云界面)

    下面小編就為大家分享一篇Android5.0以上實(shí)現(xiàn)全透明的狀態(tài)欄方法(仿網(wǎng)易云界面),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • Android抓取CSDN首頁(yè)極客頭條內(nèi)容完整實(shí)例

    Android抓取CSDN首頁(yè)極客頭條內(nèi)容完整實(shí)例

    這篇文章主要介紹了Android抓取CSDN首頁(yè)極客頭條內(nèi)容完整實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • Android自定義圖片集合

    Android自定義圖片集合

    這篇文章主要為大家分享了內(nèi)容相當(dāng)豐富的Android自定義圖片集合,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-02-02
  • Android實(shí)現(xiàn)音樂(lè)播放器歌詞顯示效果

    Android實(shí)現(xiàn)音樂(lè)播放器歌詞顯示效果

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)音樂(lè)播放器歌詞顯示效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • Android SwipeRefreshLayout超詳細(xì)講解

    Android SwipeRefreshLayout超詳細(xì)講解

    在android開(kāi)發(fā)中,使用最多的數(shù)據(jù)刷新方式就是下拉刷新了,而完成此功能我們使用最多的就是第三方的開(kāi)源庫(kù)PullToRefresh?,F(xiàn)如今,google也忍不住推出了自己的下拉組件SwipeRefreshLayout,下面我們通過(guò)api文檔和源碼來(lái)分析學(xué)習(xí)如何使用SwipeRefreshLayout
    2022-11-11
  • Android布局之LinearLayout線性布局

    Android布局之LinearLayout線性布局

    LinearLayout是線性布局控件:要么橫向排布,要么豎向排布,下面通過(guò)本篇文章給大家介紹Android布局之LinearLayout線性布局,涉及到android linearlayout 布局相關(guān)知識(shí),對(duì)本文感興趣的朋友一起學(xué)習(xí)吧
    2015-12-12
  • Android自定義控件之開(kāi)關(guān)按鈕學(xué)習(xí)筆記分享

    Android自定義控件之開(kāi)關(guān)按鈕學(xué)習(xí)筆記分享

    這篇文章主要為大家分享了Android自定義開(kāi)關(guān)按鈕的學(xué)習(xí)筆記,內(nèi)容豐富,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • android實(shí)現(xiàn)百度地圖自定義彈出窗口功能

    android實(shí)現(xiàn)百度地圖自定義彈出窗口功能

    這篇文章主要介紹了android實(shí)現(xiàn)百度地圖自定義彈出窗口的功能,大家參考使用吧
    2013-11-11
  • Android進(jìn)階教程之ViewGroup自定義布局

    Android進(jìn)階教程之ViewGroup自定義布局

    這篇文章主要給大家介紹了關(guān)于Android進(jìn)階教程之ViewGroup自定義布局的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位Android開(kāi)發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 利用Kotlin實(shí)現(xiàn)破解Android版的微信小游戲--跳一跳

    利用Kotlin實(shí)現(xiàn)破解Android版的微信小游戲--跳一跳

    這篇文章主要給大家介紹了關(guān)于利用Kotlin實(shí)現(xiàn)破解Android版微信小游戲--跳一跳的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12

最新評(píng)論