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架构
==========================================================================
[]( )1.概述
----------------------------------------------------------------------
MVVM架构最早由微软提出,并在微软的桌面客户端UI框架WPF中实现,由Model、View、ViewModel三部分组成:
* **Model**:负责数据的存储及相关逻辑。
* **View**:负责界面展示。
* **ViewModel**:负责业务逻辑。
MVVM架构是MVP架构的简化版,它同样的解决了View层与Model层的隔离问题。不同于MVP架构中的View层与Presenter层之间的双向通信,MVVM架构采用了一种View层与ViewModel层绑定的方式,当ViewModel层中的UI数据或属性发生变化时,View层的UI会跟随一起变化,这样原本Presenter层中操作View层接口的逻辑通过绑定的方式被简化,层级变得更加轻量,简化后的Presenter层与View层之间只存在数据驱动的关系,Presenter层被简化成了ViewModel层。三个层级的调用关系如下图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/050e49686c6446da8b98a3fdea3671d1.jpeg#pic_center)
在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 {
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架构通过规范层级间的单向依赖关系,从而形成一层包裹一层的层级结构。如下图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/42fecf06382a4e389be3a40e5c9bce6a.jpeg#pic_center)
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 {
fun success(data: T)
fun fail(e: Throwable)
}
class GetUserInfoUseCase : UseCase<Unit, UseCaseCallback> {
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 {
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 {
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架构中三者的调用关系如下图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/ff7e0c32a7c64c8082a173496282e6b9.jpeg#pic_center)
在MVVM架构中,View会调用ViewModel执行具体的逻辑操作。而在MVI架构中,用户对View层的交互会被抽象成Intent。当交互发生时,View会发送对应的Intent到ViewModel中处理,通过Intent隔离View对ViewModel的调用。如下图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/183bdfa8930e465ca9da98b3dbee9320.jpeg#pic_center)
在MVVM架构中,ViewModel内部对View的数据与属性的维护是分散的,具体表现为每个View都会有一个Data。而在MVI架构中,这些Data将会被整合在一起,形成统一的State,如下图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/c0a8bea29f454b8a853fea9075c0464d.jpeg#pic_center)
在MVI架构中,Model层指的就是State。通过引入State,可以更加方便ViewModel的管理。同时隔离ViewModel对View的调用,如下图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/fd7cd55d7a7d41ac9b9b04544aaf2b0c.jpeg#pic_center)
这样,原本在MVVM架构中由于双向绑定引起的代码耦合问题,在MVI架构中通过引入Intent与State得以解决。同时,架构整体的数据流向更加清晰,如下图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/3164966d78e84a27882c55b084c75c3d.jpeg#pic_center)
在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())
}
})
}
结语
看到这篇文章的人不知道有多少是和我一样的Android程序员。
35岁,这是我们这个行业普遍的失业高发阶段,这种情况下如果还不提升自己的技能,进阶发展,我想,很可能就是本行业的职业生涯的终点了。
我们要有危机意识,切莫等到一切都成定局时才开始追悔莫及。只要有规划的,有系统地学习,进阶提升自己并不难,给自己多充一点电,你才能走的更远。
千里之行始于足下。这是上小学时,那种一元钱一个的日记本上每一页下面都印刷有的一句话,当时只觉得这句话很短,后来渐渐长大才慢慢明白这句话的真正的含义。
有了学习的想法就赶快行动起来吧,不要被其他的事情牵绊住了前行的脚步。不要等到裁员时才开始担忧,不要等到面试前一晚才开始紧张,不要等到35岁甚至更晚才开始想起来要学习要进阶。
给大家一份系统的Android学习进阶资料,希望这份资料可以给大家提供帮助。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
e =
state.value.copy(response = PageResponse.Fail(e), userInfo = getNetErrorData())
}
})
}
结语
看到这篇文章的人不知道有多少是和我一样的Android程序员。
35岁,这是我们这个行业普遍的失业高发阶段,这种情况下如果还不提升自己的技能,进阶发展,我想,很可能就是本行业的职业生涯的终点了。
我们要有危机意识,切莫等到一切都成定局时才开始追悔莫及。只要有规划的,有系统地学习,进阶提升自己并不难,给自己多充一点电,你才能走的更远。
千里之行始于足下。这是上小学时,那种一元钱一个的日记本上每一页下面都印刷有的一句话,当时只觉得这句话很短,后来渐渐长大才慢慢明白这句话的真正的含义。
有了学习的想法就赶快行动起来吧,不要被其他的事情牵绊住了前行的脚步。不要等到裁员时才开始担忧,不要等到面试前一晚才开始紧张,不要等到35岁甚至更晚才开始想起来要学习要进阶。
给大家一份系统的Android学习进阶资料,希望这份资料可以给大家提供帮助。
[外链图片转存中…(img-PQKywC7p-1714433209967)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!