本文作者為騰訊Bugly特約撰稿人:騰訊自選股客戶(hù)端工程師 王金波
問(wèn)題描述
做過(guò)Android開(kāi)發(fā)的人都遇到過(guò)這樣的問(wèn)題:隨著需求的變化,某些入口界面通常會(huì)出現(xiàn)UI的增加、減少、內(nèi)容變化以及跳轉(zhuǎn)界面變化等問(wèn)題。每次發(fā)生變化都要手動(dòng)修改代碼,而入口界面通常具有未讀信息提醒這樣的“小紅點(diǎn)”邏輯;一旦UI變化,“小紅點(diǎn)”邏輯也要重新計(jì)算。如果不同的RD來(lái)維護(hù)這些代碼,耦合性非常高,出錯(cuò)概率也很大。本文以自選股的個(gè)人頁(yè)卡為例(界面如下圖所示),給出了一套方案來(lái)解決動(dòng)態(tài)更新UI的問(wèn)題以及更好的解決未讀提醒的邏輯。
舊的方案(Phase out)
對(duì)于UI動(dòng)態(tài)變化的問(wèn)題,通常結(jié)合遠(yuǎn)程控制來(lái)解決。
以上圖的“資產(chǎn)管理”為例,舊的解決方案會(huì)在XML寫(xiě)死全部的item,如:“港股交易”、“基金交易”和“精品理財(cái)”這三個(gè)item。然后根據(jù)后臺(tái)傳遞過(guò)來(lái)的JSON解析出需要隱藏哪些item。點(diǎn)擊不同的item會(huì)跳轉(zhuǎn)到不同的activity(如下圖所示),這部分跳轉(zhuǎn)操作也是寫(xiě)死在代碼中的。
這解決了一部分問(wèn)題,但是如果需求新增了item,比如新增了“滬深交易”、“美股交易”,那就需要改動(dòng)現(xiàn)有代碼了。
對(duì)于未讀指示(小紅點(diǎn))功能,它的作用是,有未讀信息來(lái)了,需要在UI上面顯示一個(gè)小紅點(diǎn)提醒用戶(hù)。比如下圖的股友動(dòng)態(tài)的頭像提醒,資產(chǎn)管理的“NEW”提醒,系統(tǒng)設(shè)置的新版本提醒等。
舊的方案是定義了一個(gè)int型(32位),用它的每一位代表一個(gè)UI上的item。比如好友動(dòng)態(tài)是第1位,未讀提醒是第2位... “小紅點(diǎn)”思想是哪個(gè)item有未讀信息,則該int型對(duì)應(yīng)的那一位就置1,否則為0。一旦某個(gè)item有未讀提醒的改變,則將這個(gè)int型對(duì)應(yīng)的位改變,異步寫(xiě)入SharedPreference中,同時(shí)利用觀察者模式通知UI做更新,如下圖所示:
上述做法總體來(lái)說(shuō)大的缺陷就是沒(méi)有做到“開(kāi)放-封閉”原則。面對(duì)擴(kuò)展的時(shí)候,即添加一個(gè)item則不得不修改現(xiàn)有代碼,需要在該int型中添加一位標(biāo)志位,觀察者模式也要注冊(cè)新item。所以下面我會(huì)介紹另一種方案可以更好的解決該問(wèn)題。
新的解決方法
數(shù)據(jù)抽象
首先進(jìn)行數(shù)據(jù)的抽象,并將UI進(jìn)行分組,如下圖所示:
按照組合模式,將數(shù)據(jù)以樹(shù)形結(jié)構(gòu)組織起來(lái),表現(xiàn)“整體/部分”層次結(jié)構(gòu),如下圖所示。這樣做的好處是,可以以一致的方式來(lái)處理個(gè)別對(duì)象以及對(duì)象組合。藍(lán)色的表示節(jié)點(diǎn),而綠色的表示葉節(jié)點(diǎn)。
組合模式的類(lèi)圖,如下所示:
對(duì)UI進(jìn)行的數(shù)據(jù)抽象。無(wú)論是ListItem列表項(xiàng),還是GridView Item的項(xiàng),都采用了PersonalItem對(duì)象來(lái)表示,如下所示:
對(duì)于PersonalItem來(lái)說(shuō),有些沒(méi)有意義的方法就不實(shí)現(xiàn),如add()、remove()、getChild()等,調(diào)用它們會(huì)拋出UnsupportedOperationException()異常。
完美解決未讀提醒(小紅點(diǎn))的問(wèn)題
關(guān)于計(jì)算小紅點(diǎn),PersonalGroup類(lèi)利用組合+迭代器的模式,代碼如下:
這里使用了迭代器,用它遍歷所有PersonalComponent組件。遍歷過(guò)程中可能遇到PersonalItem也可能遇到PersonalGroup。由于它們都是PersonalComponent,且實(shí)現(xiàn)了getUnreadIndicator()方法,那我們只需調(diào)用getUnreadIndicator()即可。
如上圖所示,PersonalGroup中加載的是PersonalComponent,可能是PersonalItem也可能是PersonalGroup。組合模式的優(yōu)點(diǎn)就是無(wú)視具體類(lèi)型 -- 獲取出來(lái)的都是PersonalComponent,然后利用多態(tài),調(diào)用具體類(lèi)的getUnredIndicatorCount()方法。如果是PersonalGroup,則繼續(xù)調(diào)用它的這個(gè)方法(與此方法一樣,會(huì)開(kāi)始另一個(gè)遍歷);如果為PersonalItem,則說(shuō)明遍歷到了樹(shù)形結(jié)構(gòu)的末端(即葉節(jié)點(diǎn)),則進(jìn)行如下處理:
如果getUnreadIndicator為true,則表示該P(yáng)ersonalComponent需要顯示小紅點(diǎn)。因此,利用上述組合+迭代方式,運(yùn)用遞歸在根節(jié)點(diǎn)處進(jìn)行一次調(diào)用即可。如下圖所示,當(dāng)計(jì)算出葉節(jié)點(diǎn)“A股大賽”有未讀提醒,則它上級(jí)的groups也有未讀提醒,一直統(tǒng)計(jì)到根節(jié)點(diǎn)。
getUnredIndicatorCount()是每一個(gè)item自己來(lái)決定自己是否需要展示小紅點(diǎn)的方法。這就是將局部與整體解耦了。整體上面,需要計(jì)算小紅點(diǎn),至于如何計(jì)算則委托給具體類(lèi)來(lái)實(shí)現(xiàn)。即面向?qū)ο笾械膶?"做什么" 與 "怎么做"分開(kāi)。RD可以從中解放出來(lái),不必關(guān)注整體實(shí)現(xiàn),只需關(guān)注自己的實(shí)現(xiàn)即可。比如,需要在“資產(chǎn)管理”中添加“美股交易”,RD只需添加“美股交易”的內(nèi)容即可。下一節(jié)會(huì)說(shuō)明,這部分內(nèi)容也由遠(yuǎn)程控制來(lái)代勞了,遠(yuǎn)程控制傳遞過(guò)來(lái)的Date與本地存儲(chǔ)的Date比較,如果是新的Date值,則證明這個(gè)item為“NEW”,則對(duì)應(yīng)的小紅點(diǎn)需要顯示。
遠(yuǎn)程控制動(dòng)態(tài)更新UI
當(dāng)遠(yuǎn)程控制發(fā)生變化時(shí)(5分鐘主動(dòng)發(fā)一次請(qǐng)求),通過(guò)解析遠(yuǎn)程控制接口返回的JSON串,生成PersonalItem對(duì)象的列表。其中每一項(xiàng)對(duì)應(yīng)UI上面的一個(gè)item。需要注意的是,這里還包含了一個(gè)URL,它是點(diǎn)擊UI控件跳轉(zhuǎn)的URL。以“資產(chǎn)管理”為例,它包含“滬深交易”、“基金交易”等子項(xiàng)。當(dāng)點(diǎn)擊任意一個(gè)子項(xiàng)的時(shí)候啟動(dòng)的是同一個(gè)Activity - WebviewActivity,它包含一個(gè)WebView控件。因?yàn)槊總€(gè)子項(xiàng)的跳轉(zhuǎn)URL不一樣,所以這個(gè)WebView load了不同的URL,即完成了跳轉(zhuǎn)不同界面的問(wèn)題。 然后按照上面描述的樹(shù)形結(jié)構(gòu),把PersonalItem放到Groups中。如下圖所示:
Model存儲(chǔ)了待顯示的數(shù)據(jù)結(jié)構(gòu)。這份數(shù)據(jù)通過(guò)Parser的解析生成UI的內(nèi)容。過(guò)程如下圖所示:
Parser模塊是一個(gè)遞歸函數(shù),遞歸的對(duì)Model進(jìn)行解析。并將解析出來(lái)的List Item、Grid Group、GridView Item加載各自的XML文件,在程序中動(dòng)態(tài)的添加UI組件。其中onClick事件是在定義PersonalItem的時(shí)候已經(jīng)寫(xiě)好了回調(diào)。例如,“資產(chǎn)管理”屬于Grid Group,其子項(xiàng)“滬深交易”、“基金交易”等屬于GridView Item。在上述“Build PersonalItem Objects”步驟中,已經(jīng)定義了onClick方法,調(diào)用onClick方法跳轉(zhuǎn)至WebViewActivity,這個(gè)Activity會(huì)加載不同GridView Item的URL,從而實(shí)現(xiàn)點(diǎn)擊不同item跳轉(zhuǎn)不同頁(yè)面的目的。
Note:
對(duì)于ListItem元素,即上圖的列表項(xiàng)(不是GridView元素),并沒(méi)有實(shí)現(xiàn)遠(yuǎn)程更新的策略。因?yàn)樗鼈兲D(zhuǎn)的邏輯是跳轉(zhuǎn)到各自的Activity,是固定不變的;并且它們的文字描述、圖標(biāo)、是否隱藏均不需要后臺(tái)來(lái)控制更新。故實(shí)際項(xiàng)目中,只對(duì)GridView內(nèi)容作了遠(yuǎn)程控制動(dòng)態(tài)更新UI機(jī)制的處理。
另外,在通過(guò)遠(yuǎn)程控制動(dòng)態(tài)更新UI的過(guò)程中也遇到了一些坑,比如遠(yuǎn)程控制更新的時(shí)刻,恰好用戶(hù)退出App,此時(shí)系統(tǒng)剛好銷(xiāo)毀Activity。那么在執(zhí)行到上述Parser模塊的inflateUI的時(shí)候就需要判斷當(dāng)前上下文是否為空,如果為空則直接退出。
結(jié)論與數(shù)據(jù)
本文通過(guò)將UI數(shù)據(jù)進(jìn)行抽象,利用組合模式進(jìn)行數(shù)據(jù)的構(gòu)建,利用遞歸的方式將數(shù)據(jù)映射為UI,同時(shí)處理了點(diǎn)擊事件。數(shù)據(jù)源則可以通過(guò)遠(yuǎn)程控制動(dòng)態(tài)的更新,RD從中解放。另外,組合+迭代器的方式完美的解決了小紅點(diǎn)的問(wèn)題,遵循了“開(kāi)放-封閉”原則,將“做什么”與“怎么做”分開(kāi)。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。
文章標(biāo)題:Android:結(jié)合遠(yuǎn)程控制來(lái)解決安卓問(wèn)題-創(chuàng)新互聯(lián)
標(biāo)題網(wǎng)址:http://aaarwkj.com/article30/dppjso.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、外貿(mào)建站、靜態(tài)網(wǎng)站、網(wǎng)頁(yè)設(shè)計(jì)公司、微信小程序、全網(wǎng)營(yíng)銷(xiāo)推廣
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容