寫在開頭:
????? Android源碼的過程,動輒好幾千行、好幾萬行代碼,大多數人肯定是看著就雙卵一緊、背脊一涼,一句“我CAO NI MA BI”就close掉頁面,略過了!而且也或多或少的會覺得,這些東西都應該是大神級別的人物寫出來的東西,真害怕自己領略不到大神們的奇思妙想和鬼斧神工。?
????? 對我而言,最開始也是這樣的。但是當鄙人靜下心來,緊一緊本人的蛋,收一收菊花,邊扣著鼻屎,邊咬著牙去慢慢看的時候,首先發現的是在注釋里還是有好些拼寫錯誤(看來,是人寫的東西,就一定會有錯誤和漏洞的啊),接著就是有些類的層次設計真是看不懂如此的意義在哪里,還有就是類結構的設計以及方法的邏輯結構和處理是好生奇怪。或許是我才疏學淺吧,真沒看出來大師、大神們、或者上古神獸們的匠心獨運在哪里。這里會陸續羅列一些我在閱讀源碼的過程中的一些分析和疑問,與所有的開發者一起共勉!
以上三張圖片沒啥名堂,只是這篇內容所關注的東西的核心信息的介紹而已。接著來看這個類的幾個核心代碼:
getSpanEnd(Object what)、getSpanFlag(Object what)的處理和getSpanStart(Object what)是一樣的結構。那么可以得知成員變量mSpanData的存儲結構是[{start, end, flag},? , , ]邏輯上是一個int[][3]的二維數組,只是以一維數組的形式來操作。
那么問題來了:每次操作都得有四則運算(涉及到數組遍歷是將產生大量的乘法運算),而且相關數據分布在兩個數組之中(mSpans、mSpanData),為啥不單獨設計一個數據結構,來維護所有內容,在邏輯上更直觀,處理起來也更方便。這里僅僅只是為了炫技增加代碼的復雜度,還是Java中沒有像C那樣的數據結構,只能設計單獨的一個類,相比用內容拆分以及在數組處理技巧上的時間耗費來換取維護一個類數組的內存空間消耗,作者通過效率考慮選擇前者,是真的有啥特別的深意么?不懂!
我們再來看核心的三個方法:
這個很好理解,沒啥可說的,但是看看setSpan方法,可是讓我大吃一驚,好生奇怪:
第一個if語句對flag的判斷,就讓我好生奇怪,估計是我確實不能完全理解這個類的使用,setSpan為啥要先對本來要set的flag做判斷,那這個set還有啥意義?而if(mSpanCount + 1 >= mSpans.length)這個if判斷,要知道mSpans.length和mSpanCount++都得在該方法里面被操作的(而且還是這個if語句之后),永遠都會是true(排除在線程不安全的情況下)的if判斷,有何意義?難道真的是我才疏學淺?
接著也是最后的超級大招兒:
這個方法,寫得是相當的奇怪,完全不明就里。按我們正常的思維,一個span生效的范圍就是字串的某一子串,那么for循環內部的那幾個if條件判斷,就是好生奇怪了!不懂!還是for循環內,count作為if條件,來對篩選結果做處理,大家不覺得有些怪怪的。是不是感覺很是多此一舉,直接累加返回結果數組不久行了么。以及臨時變量ret1做程序結構的輔助,有這個必要么?更不用說跳出循環后,在對最后的返回結果處理的時候,真真的不明白代碼這樣寫的意義何在,最初直接一個預分配一個T[0]的ret數組,有匹配結果后,直接append,我想效率不會是很差的吧!或者給一個T結構的鏈表,最后結果處理成T[]返回!作者這樣count==0、count==1的設計,哎呀,真心的看不懂啊!
OK,分析到這里就結束了,本來不是一個和復雜的類,代碼也不是很多,只是我在看的時候,遇到的這些個問題,確實讓我好生困惑,這里寫出來,希望有大神能看到,來鄙視我也好、解答困惑也好,給些我能明白的解釋!要說我去按我的思路去重寫該類,也不是不可以,只是因為我有如此多的困惑,說明可能我還沒能完全理解的這個類的結構和用法,不敢冒此大不韙!
Anyway,這個SpannableString類名改成DecratableString或許更貼近它實際用法的意思!不是么!