亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

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

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

如何理解Android架構

發布時間:2021-10-14 15:42:09 來源:億速云 閱讀:120 作者:iii 欄目:移動開發

本篇內容介紹了“如何理解Android架構”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

1. 模塊化的意義何在?

1.1 基本概念以及底層思想

所有的模塊化都是為了滿足單一設計原則 (字面意思理解即可),一個函數或者一個類再或者一個模塊,職責越單一復用性就越強,同時能夠間接降低耦合性

在軟件工程的背景下,改動就會有出錯的可能,不要說"我注意一點就不會出錯"這種話,因為人不是機器。我們能做的就是盡可能讓模塊更加單一,職責越單一影響到外層模塊的可能性就越小,這樣出錯的概率也就越低。

所以模塊化核心思想即:單一設計原則

1.2 我們要基于哪些特性去做模塊化劃分?

做模塊化處理的時候盡量基于兩種特性進行功能特性、業務特性

功能特性

  • 網絡、圖片加載等等都可稱之為功能特性。比如網絡:我們可以將網絡框架的集成、封裝等等寫到同一個模塊(module、package等)當中,這樣可以增強可讀性(同一目錄一目了然)、降低誤操作概率,方便于維護也更加安全。同時也可將模塊托管至遠程如maven庫,可供多個項目使用,進一步提升復用性

業務特性

  • 業務特性字面意思理解即可,就是我們常常編寫的業務,需要以業務的特性進行模塊劃分

為什么說業務特性優先級要高于功能特性?

舉個例子如下圖:

如何理解Android架構

相信很多人見過或者正在使用這種分包方式,在業務層把所有的Adapter、Presenter、Activity等等都放在對應的包中,這種方式合理嗎?先說答案不合理,首先這已經是在業務層,我們做的所有事情其實都在為業務層服務,所以業務的優先級應該是最高的,我們應當優先根據業務特性將對應的類放入到同一個包中。

功能模塊核心是功能,應當以功能進行模塊劃分。業務模塊核心是業務,應當優先以業務進行模塊劃分,其次再以功能進行模塊劃分。

1.3 Android如何做分層處理?

前端開發其實就是做數據搬運,再展示到視圖中。數據與視圖是兩個不同的概念,為了提高復用性以及可維護性,我們應當根據單一設計原則我們應當將二者進行分層處理,所以無論是MVC、MVP還是MVVM最核心的點都是將數據與視圖進行分層。

絆腳石:

  • 通常來講,我們通過網絡請求拿到數據結構都是后端定義的,這也就意味著視圖層不得不直接使用后端定義的字段,一旦后端進行業務調整會迫使我們前端從數據層-->視圖層都會進行對應的改動,如下偽代碼所示: 

//原始邏輯 數據層 Model{     title } UI層 View{     textView = model.title }  //后端調整后 數據層 Model{     title     prefix } UI層 View{     textView = model.prefix + model.title }

起初我們的textView顯示的是model中的title,但后端調整后我們需要在model中加一個prefix字段,同時textView顯示內容也要做一次字符串拼接。視圖層因為數據層的改動而被動做了修改。既然做了分層我們想要的肯定是視圖、數據互不干擾,如何解決?往下看...

1.4 Data Mapper或許是解藥

Data Mapper是后端常用的一個概念,一般情況下他們是不會直接使用數據庫里面的字段,而是加一個Data  Mapper(數據映射)將數據庫表轉按需換成Java Bean,這樣做的好處也很明顯,表結構甭管怎么折騰都不會影響到業務層代碼。

對于前端我覺得可以適當引入Data Mapper,將后端數據轉換成本地模型,本地模型只與設計圖對應,將后端業務與視圖完全隔離。這也就解決了 1.3  面臨的問題,具體方式如下:

數據層 Model{     title     prefix } 本地模型(與設計圖一一對應) LocalModel{     //將后端模型轉換為本地模型     title = model.prefix + model.title } UI層 View{     textView = localModel.title }

LocalModel相當于一個中間層,通過適配器模式將數據層與視圖層做隔離。

前端引入Data  Mapper后可以脫離后端進行開發,只要需求明確就可以做視圖層的開發,完全不需要擔心后端返回什么結構、字段。并且這種做法是一勞永逸的,比如后端需要對某些字段做調整,我們可以不暇思索直奔數據層,涉及到的調整100%不會影響到視圖層

注意點:

  • 當下有一部分公司為了將前后端分離更徹底,由前端開發人員提供Java  Bean(相當于LocalModel)的結構,好處也很明顯,更多的業務內聚到后端,很大程度提升了業務的靈活性,畢竟App發一次版成本還是比較大的。面對這種情況我們其實沒必要再編寫Data  Mapper。所以任何架構設計都要結合實際情況,適合自己的才是最好的。

1.5 無處安放的業務邏輯

關于業務邏輯其實是一個很籠統的概念,甚至可以將任意一行代碼稱之為業務邏輯,如此寬泛的概念我們該如何去理解?我先大致將它分為兩個方面:

  • 界面交互邏輯:視圖層的交互邏輯,比如手勢控制、吸頂懸浮等等都是根據業務需要實現的,所以嚴格來說這部分也屬于業務邏輯。但這部分業務邏輯一般在視圖層實現。

  • 數據邏輯:這部分是大家常說的業務邏輯,屬于強業務邏輯,比如根據不同用戶類型獲取不同數據、展示不同界面,加上Data  Mapper一系列操作其實就是給后端兜底,幫他們補全剩余邏輯而已。為了方便大家理解下文我將數據邏輯統稱為業務邏輯。

前面我們說到,Android開發應該具備數據層跟視圖層,那業務邏輯放在哪一層比較合適呢?比如MVVM模式下大家都說將業務邏輯放到ViewModel處理,這么說也沒有太大的問題,但如果一個界面足夠復雜那對應的ViewModel代碼可能會有成百上千行,看起來會很臃腫可讀性也非常差。最重要的一點這些業務很難編寫單元測試用例。

關于業務邏輯我建議單獨寫一個use case處理。

use case通常放在ViewModel/Presenter與數據層之間,業務邏輯以及Data Mapper都應該放在use  case中,每一個行為對應一個use case。這樣就解決了ViewModel/Presenter臃腫的問題,同時更方便編寫測試用例。

注意點:

  • 好的設計都是特定場景解決特定問題,過度設計不僅解決不了任何問題反而會增加開發成本。以我目前經驗來看Android開發至少一半的場景都很簡單:請求-->拿數據-->渲染視圖最多再加個Data  Mapper,流程很單一并且后期改動的可能也不太大,這種情況就沒必要寫一個use case,Data Mapper扔到數據層即可。

2. 合理分層是給 數據驅動UI 做鋪墊

先說結論:數據驅動UI的本質是控制反轉

2.1 什么是 控制反轉?

控制即對程序流程的控制,一般由我們開發者承擔,此過程為控制。但開發者是人所以不可避免出現錯誤,此時可以將角色做一個反轉由成熟的框架負責整個流程,程序員只需要在框架預留的擴展點上,添加跟自己的業務代碼,就可以利用框架來驅動整個程序流程的執行,此過程為反轉。

控制反轉概念和設計原則中的依賴倒置很相似,只是少了一個依賴抽象。

打個比方:

  • 現有一個HTTP請求的需求,如果想自己維護HTTT鏈接、自己管理TCP  Socket、自己處理HTTP緩存.....就是整個HTTP協議全部自己封裝,先不說這個工程能不能靠個人實現,就算實現也是漏洞百出,此時可以換個思路:通過OkHttp去實現,OkHttp是一個成熟的框架用它基本上不會出錯。個人封裝HTTP協議到使用OkHttp框架,這個過程在控制HTTP的角色上發生了一個反轉,個人--->成熟的框架OkHttp即控制反轉,好處也很明顯,框架出錯的概率遠低于個人。

2.2 什么是數據驅動UI?

通俗一點說就是當數據改變時對應的UI也要跟著變,反過來說當需要改變UI只需要改變對應的數據即可。現在比較流行的UI框架如Flutter、Compose、Vue其本質都是基于函數式編程實現數據驅動UI,它們共同的目的都是為了解決數據,UI一致性問題。

在當前的Android中可以使用DataBinding實現同樣的效果,以Jetpack  MVVM為例:ViewModel從Repository拿到數據暫存到ViewModel對應的ObservableFiled即可實現數據驅動UI,但前提是從Repository拿到的數據可以直接用,如果在Activity或者Adapter做數據二次處理再notify  UI,已經違背數據驅動UI核心思想。所以想實現數據驅動UI必須要有合理的分層(UI層拿到的數據無需處理,可以直接用),Data  Mapper恰好解決這一問題,同時也可規避大量編寫BindAdapter的現狀。

DataBinding并非函數式編程,它只是通過AbstractProcessor生成中間代碼,將數據映射到XML中

2.3 為什么說數據驅動UI底層思想是控制反轉?

當前Android生態能實現數據綁定UI的框架只有兩個:DataBinding、Compose(暫不討論)

在引入DataBinding之前渲染一條數據通常需要兩步,如下:

var title = "iOS" fun setTitle(){      //第一步更改數據源      title = "Android"      //第二個更改UI      textView = title }

共需要兩步更改數據源、更改UI,數據源跟UI有一個忘記修改便會出現BUG,千萬不要說:“兩個我都不會忘記修改”,當面臨復雜的邏輯以及十幾個甚至幾十個的數據源很難保證不出錯。這種問題可以通過DataBinding解決,只需更改對應的ObservableFiledUI便會同步修改,控制UI狀態也從個人反轉到的DataBinding,個人疏忽的事情DataBinding可不會。

所以說數據驅動UI底層思想是控制反轉

2.4 為什么引入Diff?

引入diff之前:

  • RecyclerView想要實現動態刪除、添加、更新需要分別手動更新數據和UI,這樣在中間插了一道并且分別更新數據和UI已經違背了前面所說的數據驅動UI,而我們想要的是不管刪除、添加或者更新只有一個入口,只要改變數據源就會驅動UI做更新,想要滿足這一原則只能改變數據源后對RecyclerView做全部刷新,但這樣會造成性能問題,復雜的界面會感到明顯的卡頓。

引入diff之后:

  • Diff算法通過對oldItem和newItem做差異化比對,會自動更新改變的item,同時支持刪除、添加的動畫效果,這一特性解決了RecyclerView需要實現數據驅動UI的性能問題

3 為什么我建議使用 函數式編程

3.1 什么是 函數式編程?

  • 一個入口,一個出口。

  • 不在函數鏈內部執行與運算本身無關的操作

  • 不在函數鏈內部使用外部變量(實際上這一條很難遵守,可以適當突破)

說的通俗點就是給定一個初始值,經過函數鏈的運行會得到一個目標值,運算的過程中外部沒有插手的權限,同時不做與本身無關的操作,從根本上解決了不可預期錯誤的產生。

舉個例子:

//Kotlin代碼  listOf(10, 20).map {    it + 1 }.forEach {    Log.i("list", "$it") }

上面這種鏈式編程就是標準的函數式編程,輸入到輸出之間開發者根本沒有插手的機會(即Log.i(..)之前開發者沒有權限處理list),所以整個流程是100%安全的,RxJava、Flow、鏈式高階函數都是標準的函數式編程,它們從規范層面解決數據安全問題。所以我建議在Kotlin中  碰到數據處理盡量使用鏈式高階函數(RxJava、Kotlin Flow亦然)。

3.2 Android視圖開發可以借鑒函數式編程思想

Android視圖開發大都遵循如下流程:請求-->處理數據-->渲染UI,這一流程可以借鑒函數式編程,將請求作為入口,渲染做為出口,在這個流程中盡量不做與當前行為無關的事(這也要求ViewModel,Repository中的函數要符合單一原則)。這樣說有點籠統,下面舉個反例:

View{        //刷新        fun refresh(){            ViewModel.load(true)        }        //加載更多        fun loadMore(){            ViewModel.load(false)        }    }     ViewModel{        //加載數據        load(isRefresh){            if (isRefresh){                //刷新            }else{                //加載更多            }        }    }

View層有刷新、加載更多兩種行為,load(isRefresh)一個入口,兩個出口。面臨的問題很明顯,修改刷新或加載更多都會對對方產生影響,違反開閉原則中的閉(對修改關閉:行為沒變不準修改源代碼),導致存在不可預期的問題產生。可以借鑒函數式編程思想對其進行改進,將ViewModel的load函數拆分成refresh和loadMore,這樣刷新和加載更多兩種行為、兩個入口、兩個出口互不干涉,通過函數的銜接形成兩條獨立的業務鏈條。

函數式編程可以約束我們寫出規范的代碼,面對不能使用函數式編程的場景,我們可以嘗試自我約束往函數式編程方向靠攏,大致也能實現相同的效果。

“如何理解Android架構”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

丰台区| 福安市| 龙游县| 德令哈市| 安西县| 台东县| 华亭县| 沐川县| 沾化县| 宁乡县| 曲沃县| 永仁县| 鄂尔多斯市| 岑巩县| 望都县| 忻城县| 贵德县| 当涂县| 城口县| 万盛区| 达拉特旗| 德保县| 象州县| 清镇市| 合作市| 富川| 高雄县| 平凉市| 乌恰县| 嘉黎县| 云浮市| 缙云县| 屏东县| 韶山市| 磐石市| 微博| 洛南县| 聊城市| 武强县| 昭平县| 体育|