Android架构演进史

  • Model:负责数据的存储及相关逻辑。

  • View:负责界面展示。

  • ViewModel:负责业务逻辑。

MVVM架构是MVP架构的简化版,它同样的解决了View层与Model层的隔离问题。不同于MVP架构中的View层与Presenter层之间的双向通信,MVVM架构采用了一种View层与ViewModel层绑定的方式,当ViewModel层中的UI数据或属性发生变化时,View层的UI会跟随一起变化,这样原本Presenter层中操作View层接口的逻辑通过绑定的方式被简化,层级变得更加轻量,简化后的Presenter层与View层之间只存在数据驱动的关系,Presenter层被简化成了ViewModel层。三个层级的调用关系如下图所示:

在这里插入图片描述

在MVVM架构的早期发展中, 开发者们使用谷歌官方的DataBinding框架实现数据与视图的绑定,但DataBinding框架使用复杂,且每当有一处代码需要修改,就会联动修改多处代码。后来,谷歌官方推荐使用Jetpack组件集中的LiveData+ViewModel。通过使用LiveData+ViewModel,大大减少了在使用MVVM架构中模版代码的编写。再后来,为了更好的在协程中使用MVVM架构,以及更方便的编写流式代码,谷歌官方推荐使用StateFlow。

MVVM架构既做到了View层与Model层的隔离,又保证了ViewModel层的简洁不臃肿。View层与ViewModel层的交互完全依赖数据驱动,方便层级的逻辑复用与测试以及多人的协作开发。但同时,由于MVVM架构比MVC架构和MVP架构更抽象,因此在使用时需要编写更多的模版代码。当UI界面复杂时,由于每个UI需要有不同的数据,因此会造成数据过于分散不易维护。

2.例子


点击按钮从网络获取用户信息,经过解析后展示到界面上。

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>) {

        // 模拟网络获取

        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架构

===========================================================================

1.概述


Clean架构由Robert.C.Martin(Bob大叔)提出,最基础的Clean架构由Entities(实体层)、Use Cases(用例层)、Interface Adapters(接口适配层)、Frameworks & Drivers(框架驱动层)四部分组成:

  • Entities:用于封装企业业务规则,指业务的核心数据模型和接口,一般情况下不会发生变化,只有当业务规则改变才会改变实体层。

  • Use Cases:用于封装软件应用的业务规则,包含实现整个应用所需全部功能的用例,通过调用各种实体的规则实现用例的功能。用例层的改变不会影响实体层,同时外部UI与数据库的改变也不会影响到用例层。

  • Interface Adapters:用于将外部数据转换为实体层与用例层需要的数据结构或将实体层与用例层返回的数据转换为外部需要的数据结构。Clean-MVP中Presenter就是在这一层。

  • Frameworks & Drivers:由一些框架与工具组成,如数据库、UI框架等。这层更多的是用于编写技术细节,而不需要考虑业务逻辑。

Clean架构通过规范层级间的单向依赖关系,从而形成一层包裹一层的层级结构。如下图所示:

在这里插入图片描述

Clean架构的层级并不是固定的。根据不同的业务特点,Clean架构也可有更多的层级(最少四层)。由此可见,Clean架构并非传统意义上的架构,它更像是一种理念。Clean架构可以与MVC架构、MVP架构、MVVM架构结合形成Clean-MVC架构、Clean-MVP架构、Clean-MVVM架构。谷歌官方借鉴Clean的理念推出Clean-MVVM架构。

Clean架构具有单向依赖、层级分明、数据驱动的优点。因此在Clean架构中,各个层级的代码逻辑更容易被测试,缺陷与问题更容易被定位,代码的可读性得到显著提升。Clean架构的结构十分复杂。它被称为洋葱架构,不仅是因为它层层包裹的结构,也是因为当你意识到需要写多层模版代码时,Clean架构会让你哭泣。同时,Clean架构还存在用例层代码复用率低、急剧增加的用例导致类膨胀的问题。

2.例子


点击按钮从网络获取用户信息,经过解析后展示到界面上。

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>) {

        // 模拟网络获取

        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架构

=========================================================================

1.概述


MVI架构是MVVM架构的升级版,由Model、View、Intent三部分组成:

  • Model:负责存储视图的数据和状态。

  • View:负责界面的展示。

  • Intent:负责封装与发送用户的操作。

MVI架构在MVVM架构的基础上强调数据的单向流动与状态的集中管理,保证数据的唯一性。在MVVM架构中三者的调用关系如下图所示:

在这里插入图片描述

在MVVM架构中,View会调用ViewModel执行具体的逻辑操作。而在MVI架构中,用户对View层的交互会被抽象成Intent。当交互发生时,View会发送对应的Intent到ViewModel中处理,通过Intent隔离View对ViewModel的调用。如下图所示:

在这里插入图片描述

在MVVM架构中,ViewModel内部对View的数据与属性的维护是分散的,具体表现为每个View都会有一个Data。而在MVI架构中,这些Data将会被整合在一起,形成统一的State,如下图所示:

在这里插入图片描述

在MVI架构中,Model层指的就是State。通过引入State,可以更加方便ViewModel的管理。同时隔离ViewModel对View的调用,如下图所示:

在这里插入图片描述

这样,原本在MVVM架构中由于双向绑定引起的代码耦合问题,在MVI架构中通过引入Intent与State得以解决。同时,架构整体的数据流向更加清晰,如下图所示:

在这里插入图片描述

在MVI架构中,通过状态集中管理减少了模版代码。通过数据单向流动保证了数据流向的一致性,开发者可以更方便的对状态进行跟踪与调试。MVI也存在着一些问题,由于状态集中管理,当页面功能复杂时,State易膨胀。每次更新状态时,都需要更新整体的状态,对内存有一定开销,而且不支持局部刷新。

2.例子


点击按钮从网络获取用户信息,经过解析后展示到界面上。

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>) {

        // 模拟网络获取

        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<*> -> {



## 写在最后

本次我的分享也接近尾声了,感谢你们在百忙中花上一下午来这里聆听我的宣讲,希望在接下来的日子,我们共同成长,一起进步!!!

最后放上一个大概的Android学习方向及思路(详细的内容太多了~),提供给大家:

![](https://img-blog.csdnimg.cn/img_convert/2a75cf2408c30c3910d4db4dbdc91fb6.webp?x-oss-process=image/format,png)

对于程序员来说,要学习的知识内容、技术有太多太多,这里就先放上一部分,其他的内容有机会在后面的文章向大家呈现出来,不过我自己所有的学习资料都整理成了一个文档,一直在不断学习,希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

**为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!**

Android架构师之路很漫长,一起共勉吧!

如果你觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

![](https://img-blog.csdnimg.cn/img_convert/3561616fe53b6cb7cee09bfee39aacd6.webp?x-oss-process=image/format,png)


加入社区》https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0
R.layout.activity_main)

        viewModel = ViewModelProvider(this).get(NetViewModel::class.java)



        viewModel.state().onEach {

            when (it.response) {

                is PageResponse.Success<*> -> {



## 写在最后

本次我的分享也接近尾声了,感谢你们在百忙中花上一下午来这里聆听我的宣讲,希望在接下来的日子,我们共同成长,一起进步!!!

最后放上一个大概的Android学习方向及思路(详细的内容太多了~),提供给大家:

[外链图片转存中...(img-VcYo8bih-1725736919813)]

对于程序员来说,要学习的知识内容、技术有太多太多,这里就先放上一部分,其他的内容有机会在后面的文章向大家呈现出来,不过我自己所有的学习资料都整理成了一个文档,一直在不断学习,希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

**为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!**

Android架构师之路很漫长,一起共勉吧!

如果你觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

[外链图片转存中...(img-EdpfA2DI-1725736919814)]


加入社区》https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值