Android组件内核之间组件间通信方案(四)下篇

interface EditProfileContract {

interface view {

fun setProgress(show: Boolean)

fun showEmptyFirstNameError()

fun showEmptyLastNameError( Android开源项目《ali1024.coding.net/public/P7/Android/git》 )
}

interface presenter {

fun saveProfile(firstName: String, lastName: String, bio: String, email: String, city: City, gender: String)
}
}

但是,在 MVVM 架构中,ViewModel 不再持有 View 的引用,而是通过 [LiveData](() 或 [RxJava](() 向 View 层暴露数据。一旦 View 订阅了 ViewModel,它就开始接收数据更新。这看似很完美,但当 ViewModel 想要更新 View 状态,比如显示和取消 Loading,将数据校验或服务器结果反馈到 UI 界面上,会变得非常困难。

解决方案

ViewModel 中的 LiveData 或 [Observable](() 越少越好。因此我们最好找到一种方法,可以封装需要传递给 View 层的数据和信息。在多数情况下,ViewModel 需要向 View 层暴露以下三种数据:

  • Data
  • Status
  • State
    下面将依次介绍。

Data

Data – 就是需要在 View 上展示的内容,比如用户信息的 User 实体类,或社交 Feed 流中的列表项。

val user = MutableLiveData()
val feeds = MutableLiveData()

Status

Status – 可以是任何仅需传递一次的信息,如校验错误,网络异常,或者服务器错误。
[Status.Kt](():

enum class Status {
SUCCESS,
ERROR,
NO_NETWORK,
EMPTY_FIRST_NAME,
EMPTY_LAST_NAME,
EMPTY_CITY,
INVALID_URI
}

LiveData 没有提供任何开箱即用的方法,但在 Google 的官方示例中,有一个 [SingleLiveEvent](() 的实现,可以解决这个问题。

一个生命周期感知的被观察者,仅在订阅后发送新的更新,常用于导航和 Snackbar 消息等事件。
这可以避免一些常见问题:在配置变更(如屏幕旋转)期间,如果观察者处于活动动态,SingleLiveEvent 将会发送更新事件。
它继承于 MutableLiveData,是一个被观察者,即使对外暴露了 SingleLiveEvent#setValue()SingleLiveEvent#call() 方法,
注意:只有一个观察者会受到更新通知。

新建一个 SingleLiveEvent 用来向 View 层暴露 Status 数据。
[EditProfileViewModel.Kt](():

private val status = SingleLiveEvent()

fun getStatus(): LiveData {
return status
}

fun handleImage(intent: Intent?) {
intent?.data?.let {
avatar.value = it.toString()
} ?: run { status.value = Status.INVALID_URI }
}

View 只关心 Status 数据,并根据不同的状态或错误执行对应的逻辑。如下实例,我们能很方便地根据每个错误显示不同的 Toast 或 Snackbar。
[EditProfileFragment.Kt](():

viewModel.getStatus().observe(this, Observer { handleStatus(it) })

private fun handleStatus(status: Status?) {
when (status) {
Status.EMPTY_FIRST_NAME -> Toast.makeText(activity, “Please enter your first name!”, Toast.LENGTH_SHORT).show()
Status.EMPTY_LAST_NAME -> Toast.makeText(activity, “Please enter your last name”, Toast.LENGTH_SHORT).show()
Status.EMPTY_CITY -> Toast.makeText(activity, “Please choose your home city”, Toast.LENGTH_SHORT).show()
Status.INVALID_URI -> Toast.makeText(activity, “Unable to load the photo”, Toast.LENGTH_SHORT).show()
Status.SUCCESS -> {
startActivity(HomeFragment.newIntent(activity))
activity.finish()
}
else -> Toast.makeText(activity, “Something went wrong, please try again!”, Toast.LENGTH_SHORT).show()
}
}

State

State – 即 UI 状态,比如加载进度条和 Dialog 等,每次开始订阅 ViewModel 的数据时,ViewModel 应该把这些 UI 状态通知给 V 《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》开源 iew 层。一种简单的做法是,我们可以创建一个数据类来保存这些状态。
[EditProfileState.Kt](():

data class EditProfileState(
var isProgressIndicatorShown: Boolean = false,
var isCityDialogShown: Boolean = false,
var isGenderDialogShown: Boolean = false)

然后在 ViewModel 中创建一个 MutableLiveData,用来包装这个 EditProfileState。由于 ViewModel 只会暴露 LiveData 给 View 层,因此我们应该提供 setter 方法,便于 View 更新此状态。
[EditProfileViewModel.kt](():

private val state = MutableLiveData()

fun getState(): LiveData {
return state
}

fun setProgressIndicator(isProgressIndicatorShown: Boolean) {
state.value?.isProgressIndicatorShown = isProgressIndicatorShown
}

fun setCityDialogState(isCityDialogShown: Boolean) {
state.value?.isCityDialogShown = isCityDialogShown
}

fun setGenderDialogState(isGenderDialogShown: Boolean) {
state.value?.isGenderDialogShown = isGenderDialogShown
}

最后,根据上面的 State 状态数据,决定 Dialog 的显示和取消。
[EditProfileFragment.Kt](():

viewModel.getState().observe(this, Observer { handleState(it) })

private fun handleState(state: EditProfileState?) {
if (state?.isCityDialogShown == true) {
showCitySelectionDialog()
return
}
if (state?.isGenderDialogShown == true) {
showGenderSelectionDialog()
return
}
}

#二、EventBus源码分析
##2.1EventBus简介

2.1.1EventBus

EventBus 是一个 Android 事件发布/订阅框架,通过解耦发布者和订阅者简化Android 事件传递,这里的事件可以理解为消息,本文中统一称为事件。事件传递既可用于 Android 四大组件间通讯,也可以用户异步线程和主线程间通讯等等。

传统的事件传递方式包括:Intent、Handler、BroadCastReceiver、Interface 回调,相比之下 EventBus 的优点是代码简洁,使用简单,并将事件发布和订阅充分解耦。可简化 Activities, Fragments, Threads, Services 等组件间的消息传递,可替代Intent、Handler、BroadCast、接口等传统方案,更快,代码更小,50K 左右的 jar 包,代码更优雅,彻底解耦。

2.1.2概念

最后

Android学习是一条漫长的道路,我们要学习的东西不仅仅只有表面的 技术,还要深入底层,弄明白下面的 原理,只有这样,我们才能够提高自己的竞争力,在当今这个竞争激烈的世界里立足。

人生不可能一帆风顺,有高峰自然有低谷,要相信,那些打不倒我们的,终将使我们更强大,要做自己的摆渡人。

资源持续更新中,欢迎大家一起学习和探讨。

你可能感兴趣的:(Android,经验分享,面试,android)