溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android:結(jié)合遠(yuǎn)程控制來解決安卓問題

發(fā)布時間:2020-07-02 13:04:45 來源:網(wǎng)絡(luò) 閱讀:321 作者:wjh20151022 欄目:移動開發(fā)

本文作者為騰訊Bugly特約撰稿人:騰訊自選股客戶端工程師 王金波

問題描述

做過Android開發(fā)的人都遇到過這樣的問題:隨著需求的變化,某些入口界面通常會出現(xiàn)UI的增加、減少、內(nèi)容變化以及跳轉(zhuǎn)界面變化等問題。每次發(fā)生變化都要手動修改代碼,而入口界面通常具有未讀信息提醒這樣的“小紅點(diǎn)”邏輯;一旦UI變化,“小紅點(diǎn)”邏輯也要重新計(jì)算。如果不同的RD來維護(hù)這些代碼,耦合性非常高,出錯概率也很大。本文以自選股的個人頁卡為例(界面如下圖所示),給出了一套方案來解決動態(tài)更新UI的問題以及更好的解決未讀提醒的邏輯。




舊的方案(Phase out)

對于UI動態(tài)變化的問題,通常結(jié)合遠(yuǎn)程控制來解決。


以上圖的“資產(chǎn)管理”為例,舊的解決方案會在XML寫死全部的item,如:“港股交易”、“基金交易”和“精品理財(cái)”這三個item。然后根據(jù)后臺傳遞過來的JSON解析出需要隱藏哪些item。點(diǎn)擊不同的item會跳轉(zhuǎn)到不同的activity(如下圖所示),這部分跳轉(zhuǎn)操作也是寫死在代碼中的。




這解決了一部分問題,但是如果需求新增了item,比如新增了“滬深交易”、“美股交易”,那就需要改動現(xiàn)有代碼了。

對于未讀指示(小紅點(diǎn))功能,它的作用是,有未讀信息來了,需要在UI上面顯示一個小紅點(diǎn)提醒用戶。比如下圖的股友動態(tài)的頭像提醒,資產(chǎn)管理的“NEW”提醒,系統(tǒng)設(shè)置的新版本提醒等。





舊的方案是定義了一個int型(32位),用它的每一位代表一個UI上的item。比如好友動態(tài)是第1位,未讀提醒是第2位... “小紅點(diǎn)”思想是哪個item有未讀信息,則該int型對應(yīng)的那一位就置1,否則為0。一旦某個item有未讀提醒的改變,則將這個int型對應(yīng)的位改變,異步寫入SharedPreference中,同時利用觀察者模式通知UI做更新,如下圖所示:




上述做法總體來說最大的缺陷就是沒有做到“開放-封閉”原則。面對擴(kuò)展的時候,即添加一個item則不得不修改現(xiàn)有代碼,需要在該int型中添加一位標(biāo)志位,觀察者模式也要注冊新item。所以下面我會介紹另一種方案可以更好的解決該問題。

新的解決方法

數(shù)據(jù)抽象


首先進(jìn)行數(shù)據(jù)的抽象,并將UI進(jìn)行分組,如下圖所示:




按照組合模式,將數(shù)據(jù)以樹形結(jié)構(gòu)組織起來,表現(xiàn)“整體/部分”層次結(jié)構(gòu),如下圖所示。這樣做的好處是,可以以一致的方式來處理個別對象以及對象組合。藍(lán)色的表示節(jié)點(diǎn),而綠色的表示葉節(jié)點(diǎn)。




組合模式的類圖,如下所示:




對UI進(jìn)行的數(shù)據(jù)抽象。無論是ListItem列表項(xiàng),還是GridView Item的項(xiàng),都采用了PersonalItem對象來表示,如下所示:




對于PersonalItem來說,有些沒有意義的方法就不實(shí)現(xiàn),如add()、remove()、getChild()等,調(diào)用它們會拋出UnsupportedOperationException()異常。

完美解決未讀提醒(小紅點(diǎn))的問題


關(guān)于計(jì)算小紅點(diǎn),PersonalGroup類利用組合+迭代器的模式,代碼如下:




這里使用了迭代器,用它遍歷所有PersonalComponent組件。遍歷過程中可能遇到PersonalItem也可能遇到PersonalGroup。由于它們都是PersonalComponent,且實(shí)現(xiàn)了getUnreadIndicator()方法,那我們只需調(diào)用getUnreadIndicator()即可。




如上圖所示,PersonalGroup中加載的是PersonalComponent,可能是PersonalItem也可能是PersonalGroup。組合模式的優(yōu)點(diǎn)就是無視具體類型 -- 獲取出來的都是PersonalComponent,然后利用多態(tài),調(diào)用具體類的getUnredIndicatorCount()方法。如果是PersonalGroup,則繼續(xù)調(diào)用它的這個方法(與此方法一樣,會開始另一個遍歷);如果為PersonalItem,則說明遍歷到了樹形結(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股大賽”有未讀提醒,則它上級的groups也有未讀提醒,一直統(tǒng)計(jì)到根節(jié)點(diǎn)。




getUnredIndicatorCount()是每一個item自己來決定自己是否需要展示小紅點(diǎn)的方法。這就是將局部與整體解耦了。整體上面,需要計(jì)算小紅點(diǎn),至于如何計(jì)算則委托給具體類來實(shí)現(xiàn)。即面向?qū)ο笾械膶?"做什么" 與 "怎么做"分開。RD可以從中解放出來,不必關(guān)注整體實(shí)現(xiàn),只需關(guān)注自己的實(shí)現(xiàn)即可。比如,需要在“資產(chǎn)管理”中添加“美股交易”,RD只需添加“美股交易”的內(nèi)容即可。下一節(jié)會說明,這部分內(nèi)容也由遠(yuǎn)程控制來代勞了,遠(yuǎn)程控制傳遞過來的Date與本地存儲的Date比較,如果是新的Date值,則證明這個item為“NEW”,則對應(yīng)的小紅點(diǎn)需要顯示。

遠(yuǎn)程控制動態(tài)更新UI


當(dāng)遠(yuǎn)程控制發(fā)生變化時(5分鐘主動發(fā)一次請求),通過解析遠(yuǎn)程控制接口返回的JSON串,生成PersonalItem對象的列表。其中每一項(xiàng)對應(yīng)UI上面的一個item。需要注意的是,這里還包含了一個URL,它是點(diǎn)擊UI控件跳轉(zhuǎn)的URL。以“資產(chǎn)管理”為例,它包含“滬深交易”、“基金交易”等子項(xiàng)。當(dāng)點(diǎn)擊任意一個子項(xiàng)的時候啟動的是同一個Activity - WebviewActivity,它包含一個WebView控件。因?yàn)槊總€子項(xiàng)的跳轉(zhuǎn)URL不一樣,所以這個WebView load了不同的URL,即完成了跳轉(zhuǎn)不同界面的問題。 然后按照上面描述的樹形結(jié)構(gòu),把PersonalItem放到Groups中。如下圖所示:




Model存儲了待顯示的數(shù)據(jù)結(jié)構(gòu)。這份數(shù)據(jù)通過Parser的解析生成UI的內(nèi)容。過程如下圖所示:




Parser模塊是一個遞歸函數(shù),遞歸的對Model進(jìn)行解析。并將解析出來的List Item、Grid Group、GridView Item加載各自的XML文件,在程序中動態(tài)的添加UI組件。其中onClick事件是在定義PersonalItem的時候已經(jīng)寫好了回調(diào)。例如,“資產(chǎn)管理”屬于Grid Group,其子項(xiàng)“滬深交易”、“基金交易”等屬于GridView Item。在上述“Build PersonalItem Objects”步驟中,已經(jīng)定義了onClick方法,調(diào)用onClick方法跳轉(zhuǎn)至WebViewActivity,這個Activity會加載不同GridView Item的URL,從而實(shí)現(xiàn)點(diǎn)擊不同item跳轉(zhuǎn)不同頁面的目的。

Note:
對于ListItem元素,即上圖的列表項(xiàng)(不是GridView元素),并沒有實(shí)現(xiàn)遠(yuǎn)程更新的策略。因?yàn)樗鼈兲D(zhuǎn)的邏輯是跳轉(zhuǎn)到各自的Activity,是固定不變的;并且它們的文字描述、圖標(biāo)、是否隱藏均不需要后臺來控制更新。故實(shí)際項(xiàng)目中,只對GridView內(nèi)容作了遠(yuǎn)程控制動態(tài)更新UI機(jī)制的處理。
另外,在通過遠(yuǎn)程控制動態(tài)更新UI的過程中也遇到了一些坑,比如遠(yuǎn)程控制更新的時刻,恰好用戶退出App,此時系統(tǒng)剛好銷毀Activity。那么在執(zhí)行到上述Parser模塊的inflateUI的時候就需要判斷當(dāng)前上下文是否為空,如果為空則直接退出。

結(jié)論與數(shù)據(jù)

本文通過將UI數(shù)據(jù)進(jìn)行抽象,利用組合模式進(jìn)行數(shù)據(jù)的構(gòu)建,利用遞歸的方式將數(shù)據(jù)映射為UI,同時處理了點(diǎn)擊事件。數(shù)據(jù)源則可以通過遠(yuǎn)程控制動態(tài)的更新,RD從中解放。另外,組合+迭代器的方式完美的解決了小紅點(diǎn)的問題,遵循了“開放-封閉”原則,將“做什么”與“怎么做”分開。

 

 

Android:結(jié)合遠(yuǎn)程控制來解決安卓問題

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI