Android架構(gòu)發(fā)展進(jìn)化詳解
一.MVC架構(gòu)
1.概述
MVC架構(gòu)是第一個(gè)應(yīng)用于Android開(kāi)發(fā)的成熟架構(gòu),由Model、View、Controller三部分組成:
- Model:負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)及相關(guān)邏輯。
- View:負(fù)責(zé)界面展示。
- Controller:負(fù)責(zé)業(yè)務(wù)邏輯。
MVC架構(gòu)將代碼邏輯分成了數(shù)據(jù)邏輯、渲染邏輯、業(yè)務(wù)邏輯三部分,三部分邏輯分別封裝在Model層、View層、Controller層。理想條件下,三者呈單向調(diào)用,如下圖所示:
但實(shí)際上,由于Android中負(fù)責(zé)頁(yè)面展示的組件(Activity或Fragment)同時(shí)承擔(dān)了View層和Controller層兩部分的職責(zé),導(dǎo)致MVC架構(gòu)在實(shí)際使用中退化。退化后的MVC架構(gòu)如下圖所示:
在一些業(yè)務(wù)場(chǎng)景中,由于View層與Controller層的邏輯耦合在一起,使得二者可以相互調(diào)用,進(jìn)一步衍生出調(diào)用關(guān)系更加復(fù)雜的MVC架構(gòu),如下圖所示:
此時(shí)的MVC架構(gòu)僅保持了Model層的獨(dú)立,而View層和Controller層沒(méi)有得到有效的隔離。
2.例子
點(diǎn)擊按鈕從網(wǎng)絡(luò)獲取用戶信息,經(jīng)過(guò)解析后展示到界面上。
1)Model層
data class UserInfo( var name: String, var age: Int, var height: Int, var weight: Int ) interface NetResponse<T> { fun onSuccess(data: T) fun onError(e: Throwable) } class NetModel { fun getUserInfo(callback: NetResponse<UserInfo>) { // 模擬網(wǎng)絡(luò)獲取 val dataStr = getStringFromNet() val info = dataStr.parseJson<UserInfo>() return callback.onSuccess(info) } }
2)Controller層
class MainActivity : AppCompatActivity() { private val netModel = NetModel() // Controller調(diào)用Model private fun getUserInfo(callback: (UserInfo) -> Unit) { netModel.getUserInfo(object : NetResponse<UserInfo> { override fun onSuccess(data: UserInfo) { callback.invoke(data) } override fun onError(e: Throwable) { callback.invoke(getNetErrorData()) } }) } private fun getNetErrorData(): UserInfo { return UserInfo(name = "", age = 0, height = 0, weight = 0) } }
3)View層
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) btnNet?.setOnClickListener { // View調(diào)用Controller getUserInfo { tvName?.text = it.name tvAge?.text = it.age.toString() tvHeight?.text = it.height.toString() tvWeight?.text = it.weight.toString() } } } }
在MVC架構(gòu)中,Controller實(shí)際上就是對(duì)Model代碼的封裝,如果在btnNet的點(diǎn)擊回調(diào)中調(diào)用getUserInfo方法,則是View調(diào)用Controller。如果在點(diǎn)擊回調(diào)中直接調(diào)用netModel的getUserInfo方法,那就變成了View調(diào)用Model。
二.MVP架構(gòu)
1.概述
MVP架構(gòu)是MVC架構(gòu)的升級(jí)版,由Model、View、Presenter三部分組成:
- Model:負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)及相關(guān)邏輯。
- View:負(fù)責(zé)界面展示。
- Presenter:負(fù)責(zé)業(yè)務(wù)邏輯。
MVP架構(gòu)也將代碼邏輯分成了數(shù)據(jù)邏輯、渲染邏輯、業(yè)務(wù)邏輯三部分。與MVC架構(gòu)不同的是,在MVP架構(gòu)中,負(fù)責(zé)業(yè)務(wù)邏輯的Controller層升級(jí)為Presenter層。Presenter層不再像Controller層一樣耦合在View層中,而是作為獨(dú)立的類與View層和Model層進(jìn)行雙向的通信,三者調(diào)用關(guān)系如下圖所示:
MVP架構(gòu)有效的將View層與Model層隔離,同時(shí),由于Presenter層僅持有View層和Model層的接口,因此對(duì)于Presenter層邏輯的測(cè)試變得更加的方便。而由于所有的邏輯代碼都集中到Presenter層中,因此Presenter層變得比原本的Controller層更臃腫。
2.例子
點(diǎn)擊按鈕從網(wǎng)絡(luò)獲取用戶信息,經(jīng)過(guò)解析后展示到界面上。
1)Model層
data class UserInfo( var name: String, var age: Int, var height: Int, var weight: Int ) interface NetResponse<T> { fun onSuccess(data: T) fun onError(e: Throwable) } class NetModel { fun getUserInfo(callback: NetResponse<UserInfo>) { // 模擬網(wǎng)絡(luò)獲取 val dataStr = getStringFromNet() val info = dataStr.parseJson<UserInfo>() return callback.onSuccess(info) } }
2)Presenter層
class Presenter(private val view: IView) { private val model = NetModel() fun getUserInfo() { model.getUserInfo(object : NetResponse<UserInfo> { override fun onSuccess(data: UserInfo) { view.setName(data.name) view.setAge(data.age) view.setHeight(data.height) view.setWeight(data.weight) } override fun onError(e: Throwable) { val data = getNetErrorData() view.setName(data.name) view.setAge(data.age) view.setHeight(data.height) view.setWeight(data.weight) } }) } private fun getNetErrorData(): UserInfo { return UserInfo(name = "", age = 0, height = 0, weight = 0) } }
3)View層
interface IView { fun setName(name: String) fun setAge(age: Int) fun setHeight(height: Int) fun setWeight(weight: Int) } class MainActivity : AppCompatActivity(), IView { private val presenter = Presenter(this) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) btnNet?.setOnClickListener { presenter.getUserInfo() } } override fun setName(name: String) { tvName?.text = name } override fun setAge(age: Int) { tvAge?.text = age.toString() } override fun setHeight(height: Int) { tvHeight?.text = height.toString() } override fun setWeight(weight: Int) { tvWeight?.text = weight.toString() } }
三.MVVM架構(gòu)
1.概述
MVVM架構(gòu)最早由微軟提出,并在微軟的桌面客戶端UI框架WPF中實(shí)現(xiàn),由Model、View、ViewModel三部分組成:
- Model:負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)及相關(guān)邏輯。
- View:負(fù)責(zé)界面展示。
- ViewModel:負(fù)責(zé)業(yè)務(wù)邏輯。
MVVM架構(gòu)是MVP架構(gòu)的簡(jiǎn)化版,它同樣的解決了View層與Model層的隔離問(wèn)題。不同于MVP架構(gòu)中的View層與Presenter層之間的雙向通信,MVVM架構(gòu)采用了一種View層與ViewModel層綁定的方式,當(dāng)ViewModel層中的UI數(shù)據(jù)或?qū)傩园l(fā)生變化時(shí),View層的UI會(huì)跟隨一起變化,這樣原本Presenter層中操作View層接口的邏輯通過(guò)綁定的方式被簡(jiǎn)化,層級(jí)變得更加輕量,簡(jiǎn)化后的Presenter層與View層之間只存在數(shù)據(jù)驅(qū)動(dòng)的關(guān)系,Presenter層被簡(jiǎn)化成了ViewModel層。三個(gè)層級(jí)的調(diào)用關(guān)系如下圖所示:
在MVVM架構(gòu)的早期發(fā)展中, 開(kāi)發(fā)者們使用谷歌官方的DataBinding框架實(shí)現(xiàn)數(shù)據(jù)與視圖的綁定,但DataBinding框架使用復(fù)雜,且每當(dāng)有一處代碼需要修改,就會(huì)聯(lián)動(dòng)修改多處代碼。后來(lái),谷歌官方推薦使用Jetpack組件集中的LiveData+ViewModel。通過(guò)使用LiveData+ViewModel,大大減少了在使用MVVM架構(gòu)中模版代碼的編寫。再后來(lái),為了更好的在協(xié)程中使用MVVM架構(gòu),以及更方便的編寫流式代碼,谷歌官方推薦使用StateFlow。
MVVM架構(gòu)既做到了View層與Model層的隔離,又保證了ViewModel層的簡(jiǎn)潔不臃腫。View層與ViewModel層的交互完全依賴數(shù)據(jù)驅(qū)動(dòng),方便層級(jí)的邏輯復(fù)用與測(cè)試以及多人的協(xié)作開(kāi)發(fā)。但同時(shí),由于MVVM架構(gòu)比MVC架構(gòu)和MVP架構(gòu)更抽象,因此在使用時(shí)需要編寫更多的模版代碼。當(dāng)UI界面復(fù)雜時(shí),由于每個(gè)UI需要有不同的數(shù)據(jù),因此會(huì)造成數(shù)據(jù)過(guò)于分散不易維護(hù)。
2.例子
點(diǎn)擊按鈕從網(wǎng)絡(luò)獲取用戶信息,經(jīng)過(guò)解析后展示到界面上。
1)Model層
data class UserInfo( var name: String, var age: Int, var height: Int, var weight: Int ) interface NetResponse<T> { fun onSuccess(data: T) fun onError(e: Throwable) } class NetModel { fun getUserInfo(callback: NetResponse<UserInfo>) { // 模擬網(wǎng)絡(luò)獲取 val dataStr = getStringFromNet() val info = dataStr.parseJson<UserInfo>() return callback.onSuccess(info) } }
2)ViewModel層
class NetViewModel : ViewModel() { private val model = NetModel() private val name = MutableLiveData<String>("") private val age = MutableLiveData<Int>(0) private val height = MutableLiveData<Int>(0) private val weight = MutableLiveData<Int>(0) fun getUserInfo() { model.getUserInfo(object : NetResponse<UserInfo> { override fun onSuccess(data: UserInfo) { name.postValue(data.name) age.postValue(data.age) height.postValue(data.height) weight.postValue(data.weight) } override fun onError(e: Throwable) { val data = getNetErrorData() name.postValue(data.name) age.postValue(data.age) height.postValue(data.height) weight.postValue(data.weight) } }) } private fun getNetErrorData(): UserInfo { return UserInfo(name = "", age = 0, height = 0, weight = 0) } fun name(): LiveData<String> = name fun age(): LiveData<Int> = age fun height(): LiveData<Int> = height fun weight(): LiveData<Int> = weight }
3)View層
class MainActivity : AppCompatActivity() { private lateinit var viewModel: NetViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewModel = ViewModelProvider(this).get(NetViewModel::class.java) viewModel.name().observe(this, Observer<String> { tvName?.text = it }) viewModel.age().observe(this, Observer<Int> { tvAge?.text = it.toString() }) viewModel.height().observe(this, Observer<Int> { tvHeight?.text = it.toString() }) viewModel.weight().observe(this, Observer<Int> { tvWeight?.text = it.toString() }) btnNet?.setOnClickListener { viewModel.getUserInfo() } } }
四.Clean架構(gòu)
1.概述
Clean架構(gòu)由Robert.C.Martin(Bob大叔)提出,最基礎(chǔ)的Clean架構(gòu)由Entities(實(shí)體層)、Use Cases(用例層)、Interface Adapters(接口適配層)、Frameworks & Drivers(框架驅(qū)動(dòng)層)四部分組成:
- Entities:用于封裝企業(yè)業(yè)務(wù)規(guī)則,指業(yè)務(wù)的核心數(shù)據(jù)模型和接口,一般情況下不會(huì)發(fā)生變化,只有當(dāng)業(yè)務(wù)規(guī)則改變才會(huì)改變實(shí)體層。
- Use Cases:用于封裝軟件應(yīng)用的業(yè)務(wù)規(guī)則,包含實(shí)現(xiàn)整個(gè)應(yīng)用所需全部功能的用例,通過(guò)調(diào)用各種實(shí)體的規(guī)則實(shí)現(xiàn)用例的功能。用例層的改變不會(huì)影響實(shí)體層,同時(shí)外部UI與數(shù)據(jù)庫(kù)的改變也不會(huì)影響到用例層。
- Interface Adapters:用于將外部數(shù)據(jù)轉(zhuǎn)換為實(shí)體層與用例層需要的數(shù)據(jù)結(jié)構(gòu)或?qū)?shí)體層與用例層返回的數(shù)據(jù)轉(zhuǎn)換為外部需要的數(shù)據(jù)結(jié)構(gòu)。Clean-MVP中Presenter就是在這一層。
- Frameworks & Drivers:由一些框架與工具組成,如數(shù)據(jù)庫(kù)、UI框架等。這層更多的是用于編寫技術(shù)細(xì)節(jié),而不需要考慮業(yè)務(wù)邏輯。
Clean架構(gòu)通過(guò)規(guī)范層級(jí)間的單向依賴關(guān)系,從而形成一層包裹一層的層級(jí)結(jié)構(gòu)。如下圖所示:
Clean架構(gòu)的層級(jí)并不是固定的。根據(jù)不同的業(yè)務(wù)特點(diǎn),Clean架構(gòu)也可有更多的層級(jí)(最少四層)。由此可見(jiàn),Clean架構(gòu)并非傳統(tǒng)意義上的架構(gòu),它更像是一種理念。Clean架構(gòu)可以與MVC架構(gòu)、MVP架構(gòu)、MVVM架構(gòu)結(jié)合形成Clean-MVC架構(gòu)、Clean-MVP架構(gòu)、Clean-MVVM架構(gòu)。谷歌官方借鑒Clean的理念推出Clean-MVVM架構(gòu)。
Clean架構(gòu)具有單向依賴、層級(jí)分明、數(shù)據(jù)驅(qū)動(dòng)的優(yōu)點(diǎn)。因此在Clean架構(gòu)中,各個(gè)層級(jí)的代碼邏輯更容易被測(cè)試,缺陷與問(wèn)題更容易被定位,代碼的可讀性得到顯著提升。Clean架構(gòu)的結(jié)構(gòu)十分復(fù)雜。它被稱為洋蔥架構(gòu),不僅是因?yàn)樗鼘訉影慕Y(jié)構(gòu),也是因?yàn)楫?dāng)你意識(shí)到需要寫多層模版代碼時(shí),Clean架構(gòu)會(huì)讓你哭泣。同時(shí),Clean架構(gòu)還存在用例層代碼復(fù)用率低、急劇增加的用例導(dǎo)致類膨脹的問(wèn)題。
2.例子
點(diǎn)擊按鈕從網(wǎng)絡(luò)獲取用戶信息,經(jīng)過(guò)解析后展示到界面上。
1)Entities層
data class UserInfo( var name: String, var age: Int, var height: Int, var weight: Int )
2)Use Cases層
interface UseCase<T, R> { fun execute(param: T, callback: R) } interface UseCaseCallback<T> { fun success(data: T) fun fail(e: Throwable) } class GetUserInfoUseCase : UseCase<Unit, UseCaseCallback<UserInfo>> { private val repository = NetRepository() override fun execute(param: Unit, callback: UseCaseCallback<UserInfo>) { repository.getUserInfo(object : NetResponse<UserInfo> { override fun onSuccess(data: UserInfo) { callback.success(data) } override fun onError(e: Throwable) { callback.fail(e) } }) } }
3)Interface Adapters層
interface NetResponse<T> { fun onSuccess(data: T) fun onError(e: Throwable) } class NetRepository { fun getUserInfo(callback: NetResponse<UserInfo>) { // 模擬網(wǎng)絡(luò)獲取 val dataStr = getStringFromNet() val info = dataStr.parseJson<UserInfo>() return callback.onSuccess(info) } } interface IView { fun setName(name: String) fun setAge(age: String) fun setHeight(height: String) fun setWeight(weight: String) } class Presenter(private val view: IView) : UseCaseCallback<UserInfo> { private val getUserInfoUseCase = GetUserInfoUseCase() fun getUserInfo() = getUserInfoUseCase.execute(Unit, this) override fun success(data: UserInfo) { view.setName(data.name) view.setAge(data.age.toString()) view.setHeight(data.height.toString()) view.setWeight(data.weight.toString()) } override fun fail(e: Throwable) { val data = getNetErrorData() view.setName(data.name) view.setAge(data.age.toString()) view.setHeight(data.height.toString()) view.setWeight(data.weight.toString()) } private fun getNetErrorData(): UserInfo { return UserInfo(name = "", age = 0, height = 0, weight = 0) } }
4)Frameworks & Drivers層
class MainActivity : AppCompatActivity(), IView { private val presenter = Presenter(this) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) btnNet?.setOnClickListener { presenter.getUserInfo() } } override fun setName(name: String) { tvName?.text = name } override fun setAge(age: String) { tvAge?.text = age } override fun setHeight(height: String) { tvHeight?.text = height } override fun setWeight(weight: String) { tvWeight?.text = weight } }
五.MVI架構(gòu)
1.概述
MVI架構(gòu)是MVVM架構(gòu)的升級(jí)版,由Model、View、Intent三部分組成:
- Model:負(fù)責(zé)存儲(chǔ)視圖的數(shù)據(jù)和狀態(tài)。
- View:負(fù)責(zé)界面的展示。
- Intent:負(fù)責(zé)封裝與發(fā)送用戶的操作。
MVI架構(gòu)在MVVM架構(gòu)的基礎(chǔ)上強(qiáng)調(diào)數(shù)據(jù)的單向流動(dòng)與狀態(tài)的集中管理,保證數(shù)據(jù)的唯一性。在MVVM架構(gòu)中三者的調(diào)用關(guān)系如下圖所示:
在MVVM架構(gòu)中,View會(huì)調(diào)用ViewModel執(zhí)行具體的邏輯操作。而在MVI架構(gòu)中,用戶對(duì)View層的交互會(huì)被抽象成Intent。當(dāng)交互發(fā)生時(shí),View會(huì)發(fā)送對(duì)應(yīng)的Intent到ViewModel中處理,通過(guò)Intent隔離View對(duì)ViewModel的調(diào)用。如下圖所示:
在MVVM架構(gòu)中,ViewModel內(nèi)部對(duì)View的數(shù)據(jù)與屬性的維護(hù)是分散的,具體表現(xiàn)為每個(gè)View都會(huì)有一個(gè)Data。而在MVI架構(gòu)中,這些Data將會(huì)被整合在一起,形成統(tǒng)一的State,如下圖所示:
在MVI架構(gòu)中,Model層指的就是State。通過(guò)引入State,可以更加方便ViewModel的管理。同時(shí)隔離ViewModel對(duì)View的調(diào)用,如下圖所示:
這樣,原本在MVVM架構(gòu)中由于雙向綁定引起的代碼耦合問(wèn)題,在MVI架構(gòu)中通過(guò)引入Intent與State得以解決。同時(shí),架構(gòu)整體的數(shù)據(jù)流向更加清晰,如下圖所示:
在MVI架構(gòu)中,通過(guò)狀態(tài)集中管理減少了模版代碼。通過(guò)數(shù)據(jù)單向流動(dòng)保證了數(shù)據(jù)流向的一致性,開(kāi)發(fā)者可以更方便的對(duì)狀態(tài)進(jìn)行跟蹤與調(diào)試。MVI也存在著一些問(wèn)題,由于狀態(tài)集中管理,當(dāng)頁(yè)面功能復(fù)雜時(shí),State易膨脹。每次更新?tīng)顟B(tài)時(shí),都需要更新整體的狀態(tài),對(duì)內(nèi)存有一定開(kāi)銷,而且不支持局部刷新。
2.例子
點(diǎn)擊按鈕從網(wǎng)絡(luò)獲取用戶信息,經(jīng)過(guò)解析后展示到界面上。
1)Model層
data class PageState( val response: PageResponse = PageResponse.Default, val userInfo: UserInfo = UserInfo() ) sealed class PageResponse { class Success<T>(data: T) : PageResponse() class Fail(e: Throwable) : PageResponse() object Loading : PageResponse() object Default : PageResponse() } data class UserInfo( val name: String = "", val age: Int = 0, val height: Int = 0, val weight: Int = 0 )
2)Intent層
sealed class UserIntent { object GetUserInfo : UserIntent() object Default : UserIntent() }
3)ViewModel層
class NetViewModel : ViewModel() { private val model = NetRepository() private val state = MutableStateFlow(PageState()) private val intent = MutableStateFlow<UserIntent>(UserIntent.Default) init { handleUserIntent() } fun state() = state.asStateFlow() fun sendIntent(userIntent: UserIntent) = viewModelScope.launch { intent.emit(userIntent) } private fun handleUserIntent() = intent.onEach { when (it) { is UserIntent.GetUserInfo -> getUserInfo() else -> {} } }.launchIn(viewModelScope) private fun getUserInfo() { state.value = state.value.copy(response = PageResponse.Loading) model.getUserInfo(object : NetResponse<UserInfo> { override fun onSuccess(data: UserInfo) { state.value = state.value.copy(response = PageResponse.Success(data), userInfo = data) } override fun onError(e: Throwable) { state.value = state.value.copy(response = PageResponse.Fail(e), userInfo = getNetErrorData()) } }) } private fun getNetErrorData(): UserInfo { return UserInfo(name = "", age = 0, height = 0, weight = 0) } } interface NetResponse<T> { fun onSuccess(data: T) fun onError(e: Throwable) } class NetRepository { fun getUserInfo(callback: NetResponse<UserInfo>) { // 模擬網(wǎng)絡(luò)獲取 val dataStr = getStringFromNet() val info = dataStr.parseJson<UserInfo>() return callback.onSuccess(info) } }
4)View層
class MainActivity : AppCompatActivity() { private lateinit var viewModel: NetViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewModel = ViewModelProvider(this).get(NetViewModel::class.java) viewModel.state().onEach { when (it.response) { is PageResponse.Success<*> -> { tvName?.text = it.response tvAge?.text = it.userInfo.age.toString() tvHeight?.text = it.userInfo.height.toString() tvWeight?.text = it.userInfo.weight.toString() } else -> {} } }.launchIn(lifecycleScope) btnNet?.setOnClickListener { viewModel.sendIntent(UserIntent.GetUserInfo) } } }
六.總結(jié)
1.從MVC架構(gòu)到MVI架構(gòu)
開(kāi)發(fā)者們?cè)谠缙诰鸵庾R(shí)到數(shù)據(jù)邏輯、業(yè)務(wù)邏輯、渲染邏輯要分離,因此引入了MVC架構(gòu)。但由于Android頁(yè)面組件的特殊性,導(dǎo)致在實(shí)際使用中MVC架構(gòu)的數(shù)據(jù)邏輯、業(yè)務(wù)邏輯與渲染邏輯并沒(méi)有完美分離,因此產(chǎn)生了MVP架構(gòu)。MVP架構(gòu)雖然解決了渲染邏輯與數(shù)據(jù)邏輯的隔離問(wèn)題,但由于Presenter層需要與View層和Model層雙向通信,導(dǎo)致承載業(yè)務(wù)邏輯的Presenter層過(guò)于臃腫,因此引入了MVVM架構(gòu)。MVVM架構(gòu)通過(guò)綁定的通信方式,解決了業(yè)務(wù)邏輯層由于層級(jí)間通信而過(guò)于臃腫的問(wèn)題。隨著時(shí)間推移,綁定框架也在不斷發(fā)展:從DataBinding到LiveData,再?gòu)腖iveData到StateFlow。由于當(dāng)界面UI復(fù)雜時(shí),MVVM架構(gòu)的數(shù)據(jù)過(guò)于分散不易維護(hù),因此產(chǎn)生了MVI架構(gòu)。MVI架構(gòu)引入了虛擬的“用戶層”,框架的數(shù)據(jù)流動(dòng)從“用戶層”開(kāi)始,到“用戶層”結(jié)束,單方向流動(dòng)。
2.從clean code到clean coder
縱觀Android架構(gòu)的發(fā)展歷程,數(shù)據(jù)邏輯、業(yè)務(wù)邏輯與渲染邏輯的分離關(guān)注點(diǎn)正在從代碼逐漸轉(zhuǎn)移到用戶,這是一種由“物”向“人”的轉(zhuǎn)變。
這種轉(zhuǎn)變?cè)贑lean架構(gòu)也中有所體現(xiàn)。Clean架構(gòu)的提出者Bob大叔早年間一直致力于保持代碼的整潔與條理清晰,于是出版了《Clean Code》。后來(lái),經(jīng)過(guò)探索研究發(fā)現(xiàn),想要保持代碼的“干凈”,最重要的還是要提升開(kāi)發(fā)者的自身素質(zhì),于是誕生了《 The Clean Coder》。Clean架構(gòu)通過(guò)復(fù)雜細(xì)致的分層設(shè)計(jì),規(guī)范每個(gè)層級(jí)的功能,通過(guò)依賴關(guān)系保證了代碼的整潔。但每層內(nèi)代碼的整潔,仍然需要開(kāi)發(fā)者通過(guò)代碼素養(yǎng)來(lái)保證。只有保持每一層代碼的整潔,整體代碼才能整潔。
3.MVI架構(gòu)之后
谷歌官方最早推薦開(kāi)發(fā)者使用MVVM架構(gòu),在MVI架構(gòu)推出后,轉(zhuǎn)而推薦使用MVI架構(gòu)。那么,在MVI架構(gòu)之后的下一個(gè)主流框架又將是什么呢?這一點(diǎn)恐怕無(wú)人知曉。但通過(guò)分析可以發(fā)現(xiàn),谷歌官方推薦使用MVI架構(gòu),本質(zhì)上是在推薦狀態(tài)集中管理和單向數(shù)據(jù)流動(dòng)的開(kāi)發(fā)思想,而這一開(kāi)發(fā)思想正好是響應(yīng)式編程的基礎(chǔ)。因此可以合理預(yù)測(cè)下一個(gè)主流架構(gòu)可能就是某個(gè)響應(yīng)式框架。谷歌官方這幾年也一直在開(kāi)發(fā)響應(yīng)式開(kāi)發(fā)框架Compose,但Compose框架在未來(lái)能否取代MVI框架仍然是個(gè)未知數(shù)。
到此這篇關(guān)于Android架構(gòu)發(fā)展進(jìn)化詳解的文章就介紹到這了,更多相關(guān)Android架構(gòu)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中src和background的區(qū)別詳解
這篇文章主要介紹了Android中src和background的區(qū)別詳解的相關(guān)資料,需要的朋友可以參考下2016-09-09Android自定義ProgressDialog進(jìn)度等待框
這篇文章主要介紹了Android自定義ProgressDialog進(jìn)度等待框,通過(guò)本文大家可以嘗試?yán)肁ndroid自定義ProgressDialog,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-01-01將Eclipse工程轉(zhuǎn)Android Studio工程的步驟與注意事項(xiàng)
這篇文章主要給大家介紹了將Eclipse工程轉(zhuǎn)Android Studio工程的方法步驟,并給大家分享了其中的一些注意事項(xiàng),文中將實(shí)現(xiàn)的步驟一步步介紹的非常詳細(xì),需要的朋友們可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11Android編程使用內(nèi)容提供者方式(ContentProvider)進(jìn)行存儲(chǔ)的方法
這篇文章主要介紹了Android編程使用內(nèi)容提供者方式進(jìn)行存儲(chǔ)的方法,涉及Android內(nèi)容提供者的創(chuàng)建,配置及針對(duì)數(shù)據(jù)的增刪改查等操作技巧,需要的朋友可以參考下2016-01-01Android抽屜布局DrawerLayout的簡(jiǎn)單使用
這篇文章主要為大家詳細(xì)介紹了Android抽屜布局DrawerLayout的簡(jiǎn)單使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06基于Android 監(jiān)聽(tīng)ContentProvider 中數(shù)據(jù)變化的相關(guān)介紹
本篇文章小編為大家介紹,基于Android 監(jiān)聽(tīng)ContentProvider 中數(shù)據(jù)變化的相關(guān)介紹。需要的朋友參考下2013-04-04Flutter實(shí)現(xiàn)底部和頂部導(dǎo)航欄
這篇文章主要為大家詳細(xì)介紹了Flutter實(shí)現(xiàn)底部和頂部導(dǎo)航欄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07Android實(shí)現(xiàn)類似IOS右滑返回的效果(原因分析及解決辦法)
這篇文章主要介紹了Android實(shí)現(xiàn)類似IOS右滑返回的效果,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2017-03-03Android tabLayout+recyclerView實(shí)現(xiàn)錨點(diǎn)定位的示例
這篇文章主要介紹了Android tabLayout+recyclerView實(shí)現(xiàn)錨點(diǎn)定位的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08