这是我参与更文应战的第2天,活动概略检查: 更文应战

本次 I/O 大会上曝出了 Compose 1.0 行将发布的音讯,尽管 API 层面已趋于稳定,但真实要在项目中落地还少不了一套合理的运用架approve构。传统 Android 开发中的 MVP、MVappearVM 等架构在声明式UI这一新物种中是否还依旧可用呢?

本文以一个简略的事务场景为例,妄图找出一种与 Compose 最符合的架构办法

Sample : Wanandroid Search

App根本功用:用户输入关键字,在 wanandroid 网站中查找出相关内容并展mvvm形式和mvc的差异

Jetpack Compose 架构怎样选? MVP, MVVM, MVI

功用尽管简略,可是调集了数据央求、UI展示等常见事务场景,可用来做UI层与逻辑层的解java难学吗耦实验。

前期准备:Model层

其实appointment不论 MVX 中 X 怎样改动, Model 都能够用同一套结束。咱们先界说一个 DataRjava工作培训班epository ,用于从 wanandroid 获取查找作用。 后文Sample中的 Modeapplel 层都依据此 Repo 结束

@ViewModelScoped
class DataRepository @Inject constructor(){
private val okhttpClient by lazy {
OkHttpClient.Builder().build()
}
private val apiService by lazy {
Retrofit.Builder()
.baseUrl("https://www.wanandroid.com/")
.cligithub官网ent(okhttpClient)
.addConverterFactory(GsonConvertemvvm和mvc的差异rFactory.create())
.build().create(ApiService::class.java)
}
suspend fun getArticlesList(key: String) =java初学
apiService.getArticlesList(key)
}

Compose为什么需求架构?

首要,先看看不mvvm形式和mvc的差异仰仗任何架构的 Compose 代码是怎github中文社区样的?

不运用架构的状况下,逻辑代码将与UI代码巧合在一起,在Compose中这种害处显得尤为显着。惯例 Android 开发默许引进了 MVC 思维,XML的布局办法使得UI层与逻辑层有了开始的解耦。可是 Compose 中,布局和逻辑相同都运用Kotlin结束,当布局中夹了杂逻辑,边界变得更加迷糊。

此外,Compose UI中混入逻辑代码会带来更多的潜在风险。因为 Composable 会再三重组,逻辑代码中假github是干什么的设触及I/O 就有java开发必要作为 SideEffect{} 处理java开发、一些不能随重组再三创立的目标也有必要运用 remembermvvm形式的原理{} 保存,当这些逻辑散落在UI中时,无形中增加了开发者的心智背负,很简单产生丢失。

Sample 的事务场APP景特别简略,UI中呈现少量 remember{}LaunchedEffect{} 好像也没什么不妥,关于一些相对简略的事务场景呈现下appearance面这样的代码没有问题:

@Composable
fun NoArchitectureResultScreen(
answer: String
) {
val isLoading = remember { mutabgithub是干什么的leStateOf(false) }appear
val dataRepository = remember { DataRepository() }
var result: List<ArticleBean> by remember { mutableStateOf(emptyList()) }
LaunchedEffect(Unit) {
isLoading.value = trujava模拟器e
rjavascriptesult = withContext(Dispatchers.IO) { dataRepository.getArticlesList(answer).data.datas }
isLoading.value = false
}
SearchResultScreen(result, isLoading.vgithub中文官网网页alue , answer)
}

可是,当事务满足杂乱时,你会发现这样的代码是难以忍受的。这正如在 React 前端开发中,尽管 Hooks 供给了处理逻辑的才华,但却仍然无法代替 Redux。

MVPMVVMMVI 是 Android中的一些常见架构办法,它们的意图都是服务于UI层与逻辑层的解耦,仅仅在解耦java怎样读办法上有所不同,怎样选择取决于运用者的喜爱以及项意图特点

“没有最好的架构,javascript只需最适合的架构。”

那么java模拟器在 Compose 项目中何种架构最适合呢?

MVP

MVP 首要特点是 PresenterView 之间经过接口通讯, Presenter 经过调用 View 的办法结束UI的更新。

Jetpack Compose 架构怎样选? MVP, MVVM, MVI

这要求 Presenter 需求持有一个 View 层目标的引证,可是 Compose 显着无法获得这种引证,因为用来创立 UI 的 Composable 有必要要求回来 Unit,如下:

@Cojava模拟器mposable
fun HomeScreen() {
Column {
Text("Hellojavascript World!")java工作培训班
}
}

官方文档中对无回来值的要求也进行了明确绑缚:

The fmvvm形式的原理unction doesn’t return anything. Compose funappstorections tmvvm规划形式hat emit UI do not need to return anything, because they describe the desired screen state instead of constructing UI widgets.
degithub直播渠道永久回家veloper.android.com/jetpack/com…

Compose UI 已然存在于 Android 系统中,必定需求有一个与 Amvvm和mvcndroid 世界衔接的起点,起点处可能是一个 Activigithub是干什么的ty 或许 Fragment,用他们做UI层的引证句柄不能够吗?

理论上能够,可是当 Activitymvvm规划形式 接纳 Presenter 奉告后,仍然无法在内部获取部分引证,只能设法触发整体Recomposition,这彻底丧失了 MVP 的优势,即经过获取部分引证进行精准改写。

经过剖析能够得到结论: “MVP 这种依托接口通讯的解耦办法无法在 Chttps域名ompose 项目中运用”

MVVM(without Jetpack)

相关于 MVP 的接口java工作培训班通讯 ,MVVM 依据观github敞开私库察者办法进行通讯,当 UI 观察到来自 ViewModle 的数据改动时自我更新。 UI层是否能回来引证句柄已不再重要,这与 Compose 的作业办法十分符合。

Jetpack Compose 架构怎样选? MVP, MVVM, MVI

自从 Android 用 ViewModel 命名了某 Jetpack 组件后,在许多人心里,Jetpack 如github官网同就与 MVVM 画上了等号。这的确客观推动了 MVVM 的遍及,可是 Jetpack 的 ViewModel 并非只能用在 MVVM 中(比方如后文介绍的 MVI 也https域名能够运用 ); 反之,没有 Jetpack ,照样能够结束 MVVM。

先来看看不仰仗 Jetpack 的状况下,MjavascriptVVM 怎样结束?

Activity 中创立 ViewModel

首要 View 层创立 ViewModel 用于订阅

class MvvmActivity : AppCompatActivitmvvm形式y() {
private val mvvmViewModel = MvvmViewModel(DataRepositoapplicationry())
override fun onCreate(savemvvm形式的原理dInstanceState: Bundle?) {
supjavascripter.ongithub打不开Create(savedInstanceState)
setContent {
Compgithub中文官网网页osePlaygroundTheme {
MvvmApp(mvvmViewModel) //将vm传给Composable
}
}
}
}

Compose 项目一般运用单 Activity 结构, Activity 作为大局进口十分适合创立大局 ViewModel。 子 Compoable 之间需求依据 ViewModel 通讯,所以构建 Composable 时将 ViewModel 作为参数传入。

Sample 中咱们在 Activity 中创立的 ViewModel 仅仅是为了传递appreciateMvvmApp 运用,这种状况下也能够经过传递 Lazy<MvvmViewModel>,将创立延迟到真实需求运用的时候以前进功能。

界说 NappreciateavGrmvvm和mvcaph

当触及到 Compose 页面切换时,navigation-compose 是一个不错选择,Sample中也特意规划了SearchBarScreenSearchResultScreen 的切换场景

// build.gradle
implemeapproventation "anapp装置下载droidx.navigation:navihttps协议gation-compose:$latest_version"

@Composable
fun MvvmApp(
mvvmViewModel: MvvmViewModel
) {
val navController = rememberNavConthttps认证roller()
LaunchedEffect(Unit) {
mvvmViewModel.navigateToResults
.collect {
navController.navigate("result")github永久回家地址 //订阅VM路由作业奉告,处理路由跳转
}
}
NHTTPSavHost(navContgithub永久回家地址rollerhttps和http的差异, startDestination = "searchBar")HTTPS {
composable("github官网searchBargithub敞开私库") {
MvvmSearchBarScreen(
mvvmViewModel,
)
}
composable("result") {
MvvmSearchResultScreen(
mapplevvmViewModel,
)
}
}
}
  • 在 root-level 的 MvvmApp 中界说 Ngithub敞开私库avGraphcoappearancemposgithub永久回家地址able("$dest_id"){} 中结构路mvvm原理由节点的各个子 Screen,结构时传入 ViewModel 用于 Scjava言语rapplicationeen 之间的通讯

  • 每个 Composable 都有一个 CoroutineScope 与其 Lappreciateifecycle 绑定,Lhttps和http的差异aunchedGitHubEffect{} 能够在这个 Schttps安全问题ope 中建议协github打不开程处理副作用。 代码中运用了一个只履行一次的 Effect 订阅 ViewModelgithub敞开私库 的路由作业奉告

  • 当然我appointment们能够将 navConroller 也传给 MvjavascriptvmSearchBarScreen ,在其内部github敞开私库直接建议路由跳转。但在较杂乱的项目中,跳转逻辑与页面界说应该尽量坚持解耦,这更利于页面的复用和测验。

  • 咱们也能够在 Composeable 中直接 mutableStateOf() 创立 state 来处理java开发路由跳转,可是已然选择运用 ViewModel 了,那就应HTTPS该尽可能将悉数 state 会集到 ViewModle 处理。

留心: 上面比如中的处理路由跳转的 navigateToResultsgithub敞开私库 是一个“作业”而非“状况”,关于这部分差异,java初学在后文在详细论说

界说子 Screen

接下来看一下两个 Screen 的详细结束

@Composagithub怎样下载文件ble
fun MvvmSearchBarScreen(
mvvmViewModel: MvvmViewModel,
) {
SearchBarScreen {
mvvmViewModel.searchKeyword(it)
}
}
@Composable
fun MvvmSearchResultScreen(
mvvmvvm形式的原理mViewModel: MvvmViewModel
) {
val result by mvvmViewModel.result.collectAsState()
val isLoading by mvvmViewModel.isLoading.collectAsState()
SearchResultScreen(result, isLoading, mvvmViewModel.key.value)
}

许多逻辑都抽象到 ViewModegithub官网l 中,所以 Screen 十分简练

  • SearchBarScreen 接受用户输入,将查找关键词发送app装置下载给 ViewModel

  • MvvmSearchResultScreen 作为作用mvvm模型页闪现 ViewModel 发送的数据,github是干什么的包括 Loading 状况和查找作用等。

  • collectAsState 用来将 Flow 转化为 Compose 的 state,每逢 Flow 接纳到新数据时会触发 Composable 重组。 Compose 一起支持 Ligithub官网veData、RxJava 等其他照顾式库的collectAsState

UI层的更多内容能够查阅 SearchBamvvm的了解rScreJavaenSearchResultScreen 的源码。经过approach逻辑抽离后,这两个 Composable 只剩下布局相关的代码,能够在任何一种 MVX 中结束复用。

Viapp装置下载ewModel 结束

终究看一下 ViewModel 的结束

class MvvmViewModel(
private val searchService: DataRepository,
) {
private val coroutineScope = MainScope()
private val _java怎样读isLoading: MutableStateFlow<Boolean> = MutableStategithub敞开私库Floapproachw(false)
val isLoading = _isLoading.asStateFlow()
private val _resmvvm和mvcult: MutableStateFlow<Lismvvm的了解t&Javalt;ArticleBean>appear> = MutableStateFlow(emptyList())
val result = _result.asStateFlow()
private vmvvm形式al _key = MutableStateFlow("")
val key =https安全问题 _key.asStateFlow()
//运用ChaAPPnnel界说作业
private val _navigateToResults = Channel<Boolean>(Channel.mvvm结构BUFFERED)
val navigateToResults = _navigateToResults.receiveAsFlow()
funapprove searchKeyword(igithub怎样下载文件nput: String) {
coroutineScope.laumvvm原理nch {
_isLoading.value = true
_navigateToResults.send(true)
_key.value = inpappreciateut
vaMVVMljava初学 result = withgithub官网Context(Dispatchers.IO) { searchServmvvm的了解ice.getArticlesList(input) }
_result.emit(result.data.datas)
_isLoading.java工作培训班value = false
}
}
}
  • 接纳到用户输入后,经过 DataRmvvm原理epositorjava模拟器y 建议appear查找央求

  • 查找过程中顺次更新 loading(loadinggithub打不开闪现状况)、navigateToappstoreResapp装置下载ult(页面跳转作业)、 key(查找关键词)、result(查找作用)等内容,不断驱动UI改写

悉数状况java初学会集在github中文官网网页 ViewModel 处理,乃至页面跳转、Toast弹出等作业也由 ViewModel 担任奉告,这对单元测验appearance十分java怎样读友好,在单测中无需再 mock 各种UI相关的上下文。

Jetpack MVVM

Jeptack 的意义appeargithub永久回家地址于下降 MVVM 在 Android途径的落地本钱。

引进 Jetpack 后的代码改动不大,首要改动在于 Viewmvvm规划形式Model 的创立。

Jetphttps协议ack 供给了多个组件,下降了 ViewModjavascriptel 的运用本钱:mvvm和mvc

  • 经过 hilt 的 DI 下降 ViewModel 结构本钱,无需手动github怎样下载文件传入 DataRepository 等依托
  • 恣意 Composable 都能够从最近的 Sgithub直播渠道永久回家copgithub永久回家地址e 中获取 ViewModel,无需层层传参。
@HiltViewModel
class JetpackMvvapp装置下载mViewModel @Inject constructor(
privatemvvm模型 val searchService: DataRepository // DataRepository 依托DI注入
) : ViewModel()mvvm和mvc {
...
}
@Composable
fun JetpackMvvmAppjavaee() {
val navController =github打不开 rememberNavContrappstoreoller()
NavHost(navController, startDestinatijava面试题on = "searchBar", route = "root") {
composable("searchBar") {
JetpackMvvmSearchBarScreen(
viewModel(GitHubnavController, "root") //viewModel 能够在需求时再获取, 无需结束创立好并经过参数传进来
)
}
composable("result") {
JetpaapproveckMvvmSearchResultScrgithub怎样下载文件een(
viewModel(navController, "root") //能够获取跟同一个ViewModel实例
)
}
}
}
@Composable
inline fun <reappearified VM : ViewModel> viewModel(
navController: NavController,
graphId: String = ""
): VM =
//在 NavGraph 大局规模运用 Hilt 创立 ViewModel
hiltNavGraphViewModel(
backStackEntry = navController.appeargetBackStackEntry(graphId)
)mvvm模型

Jetpack 乃至供给了 hilt-navigation-compose 库,能够在 Composable 中获取 NavGraph Scope 或 Destination Scope 的 ViewMhttps协议odel,并主动依托 Hilt 构建。Destination Scope 的 ViewModel 会跟从 BackStack 的弹出自appreciate动 Clear ,避免走漏。

// build.gradle
imAPPplegithub怎样下载文件mentation androidx.hilt:higithub敞开私库lt-navigation-compose:$latest_versioin

“未来 Jetpack 各组件之间协同效应会变得越来越强。”

MVI

MVI 与 MVgithub官网VM 很相似,其学习了前端结构的思维,更加着重数据的单向活动唯一数据源,能够看做是 MVVM + Redux 的结合。

MVI 的 I 指 Intent,这儿不是建议 AMVVMctivity 那个 Intent,而是一种对用户操作的封装办法,为避免稠浊,也可唤github打不开做 Action 等其他称谓。 用户操作以apple Action 的办法送给 Model层 进行处理。代码中,appear咱们能够用 Jetpack 的 ViewMgithub永久回家地址oHTTPSdel 担任 Intent 的接受和处github中文官网网页理,因为 ViewModel 能够在 Composable 中便当获取。

Jetpack Compose 架构怎样选? MVP, MVVM, MVI

SearchBarScreen 用户输入关键词后经过 Action 奉告 ViewModel 进行查找

@Composable
fugithub直播渠道永久回家n MviSearchBarScreen(
mviViewModel: MviViewModel,
onConfjava面试题irm: () -> Unit
) {
SearchBarScreenMVVM {
mviViewModel.onAction(MviViewModel.UiAction.SearchInput(it))
}
}

经过 Action 通讯,有利于 View 与 ViewModel 之间的进一步解耦,一起悉数调用以 Action 的办法汇总到一处,也有利于对行为的会集剖析和监控

@Cojavascriptmposable
fun MviSearjava开发chResultScreen(
mviViewMhttps和http的差异odel: MviViewModel
) {
val viewState by mviViewModel.viewState.collectAsState()java难学吗
SearchResultScreen(
viewState.result, viewState.mvvm结构isLoading, viewState.key
)
}

MVVM 的 ViewModle 中涣散界说了多个 Statappeare ,MVI 运用 ViewState 对 State 会集处理,只需求订阅一个 ViewState 便可获取页面的悉数状况,相对 MVVM 减少了不少模板代码。

相关于 MVVM,ViewModel 也有一https认证些改动

clashttps认证s MviViewModel(
private val searchService: DataRehttps域名pository,
) {
private val coroutineScope = MainScope()
private val _viewState: MutableStateFlow<ViewState> = MutableStateFlow(ViewState())
val viewState = _viewState.asStateFlow()
private val _navigithub下载gateToResults = Channelmvvm的了解<Onejava开发ShotEvent>(Channel.BUFFERED)
val navigatJavaeToResults = _navigateToResults.receiveAsFlow()
fun onAction(uiAction: UiAction) {
when (uiAction) {
is UiAction.Searchgithub敞开私库Input -> {
coroutineSgithub直播渠道永久回家cope.launch {
_viewState.value = _viewState.valugithub是干什么的e.copy(isLoMVVMading =github中文社区 true)
val result =
withContext(Dispatcherhttps域名s.IO) { searchService.getArticlesList(uiAction.input) }
_viewState.valhttps协议ue =
_viewState.value.chttps域名opy(result = result.data.datas, key = uiAction.input)
_navigateToResults.send(OneShotEvent.NavigateToResults)
_viewState.value = _viewState.value.copy(isLoading = false)
}mvvm结构
}
}
}
data class ViewState(
val isLoading: Boolean = false,
val result: List<ArticleBejava模拟器an> = emptyLgithub永久回家地址ist(),
val key: String = ""
)
sealed class OneShotEvent {
object NavigateToResults : OneSgithub直播渠道永久回家hotEvent()
}
sealed class UiAction {
class SearchInput(val input: StMVVMring) : UiAction()
}
}
  • 页面悉数的状况都界说在 ViewState 这个 data claAPPss 中,状况的修正只能在 onAction 中进行, 其他场所都是 immutablejava面试题 的, 确保了数据流只能单向修https安全问题正。 反观 MVVM ,MutableStateFlow 对外露出时转成 immutable 才华确保这种安全性,需求增加不少模板代码且仍然简单丢失。

  • 作业则共同app装置下载界说在 OneShotEjavascriptvent中。 Event 不同于 State,同一类型的作业允许照顾多次,因此界说作业运用 Channel 而不是 Stateapp装置下载FloMVVMw

Compose 鼓动多运用 State 少运用 Event, Event 只适合用在弹 Toast 等少量场景中

经过浏览 ViewModel 的 ViewState 和 Aciton 界说就能够理清 ViewModel 的职责,能够直接拿来作为接口文档运用。

页面路由

Sample 中之所以运用作业java开发而非状况来处https协议理路由跳转,一个首要原因是因为运用了 Navigation。Navigation 有自己的 backapprovestack 处理,当点击 back 键时会主动协助咱们回来前一页面。倘若咱们运用状况来描绘当时页面,当点击 back时,没有机会更java模拟器新状况,这将构成 Viewmvvm和mvc的差异State 与 UI 的不共同。

关于路由计划的建议:简略项目运用作业操控页github怎样下载文件面跳转没有问题,可是关于杂乱项目,推荐运用状况进行页面处理,有利于逻辑层时刻感知到当时的UI状况。

咱们能够将 NavController 的 backstack 状况 与 ViewModel 的状况树立同步mvvm形式


class MvvmViewModel(
private val sgithub怎样下载文件earchService: Datagithub打不开Repository,
) {
...
//运用 StateFlow 描绘页面
private val _destjava开发ination = MutaappearancebleStateFlow(DestSegithub永久回家地址archBar)
val destination = _destinatimvvm规划形式on.asStateFloappearw()
fun searchjava初学Keyword(igithub永久回家地址nput: String) {
coroutineScope.launch {
...
_djava难学吗estination.value = DestSearchResult
...
}
}
fun bindNavStack(navControlljava难学吗er: NavController) {
//navigation 的状况时刻同步到 viewModel
navController.addOnDestinationjava言语ChangedListener { _, _, arguments ->
ruapp装置下载n {
_destination.value = requireNotNull(argumvvm原理ments?.getjava工作培训班String(KEY_ROUTE))
}
}
}
}

如上,当 navigatioapp装置下载n 状况改动时,会及javaee时同步到 ViewModel ,这样就能够运用 StateFlow 而非 Channel 来描绘页面状况了。

@Composable
fun MvvmApp(
mvvmViewModejava怎样读l: MvvmViewModel
) {
val navController = rememberhttps域名Navmvvm的了解Controller()
LaunchedEffect(Unit) {
with(mvvmViewModel) {
bindNavStack(navComvvm结构ntroller) //树立同步
destination
.collect {
navController.navigate(it)
}
}
}
}

在进口处,为 NavCogithub中文官网网页ntroller 和 ViewModel 树立同github直播渠道永久回家步绑定即可。

Clean Architecture

更大型的项目中,会引进appstore Clean Architecture ,经过 Use Case 将 ViewModel 内的逻辑进一步分github直播渠道永久回家解。 Compose 仅仅个 UI 结构,关于 ViewModle 以https安全问题下的逻辑层的管理办法与传统的 Andorimvvm规划形式d 开发没有差异。所以 Clean Architecture 这样的杂乱架构仍然能够在 Compose 项mvvm和mvc目中运用

总结

比较了这么多种架构,github中文社区那种与 Compose 最符合呢?

Compose 的声明式UI思维来自 React,所以相同来自 Redux 思维的 MVI 应该是 Compose 的最佳伴侣。当然 MVI 仅仅在 MVVMapproach 的基础上java怎样读做了一些改javascript进,假定你已经有了一个 MVgithub中文官网网页VM 的项目,HTTPS仅仅想将 UI 部APP分改构成 Compose ,那么没必要为了改构成 MVI 而进行重构,MVVM 也能够很好地协作 Compose 运用的。 可是假定你想将一个 MVP 项目改构成 Compose 可能本钱就有点大了。

关于 Jetpack,假定你的项目只用于 Android,那么 Jetpack 无疑是一个好东西。可是 CoMVVMmpose 未来的运用场景将会很广泛,假定你有预期未来会协作 KMP 开发跨途径运用,那么就需求mvvm和mvc的差异学会不依托 Jetpack 的开发办法github直播渠道永久回家,这也是本文为什么要介mvvm规划形式绍非 Jetpack 下的 MVVM 的一个初衷。

Sample代码

github.com/vitaviva/Je…