为了账号安全,请及时绑定邮箱和手机立即绑定

【Jetpack Compose】解谜


未知渐渐变成了已知所以活着很无聊。但是世界上依旧存在很多未知,只要还有好奇心就能找到那些角落里的谜题,解开这些谜题的过程很让人上瘾,以此让自己想起解谜的乐趣:

谜题1.诡异的SnackBar

https://img1.sycdn.imooc.com//61c9f58c00017f5d08500632.jpg


谷歌官方的代码里给了一个把状态委派给其他类的例子,还算是比较容易理解,例子里面的showSnackbar方法,到了真正实现的时候大概也就是开一个协程然后调用scaffoldState.snackbarHostState.showSnackbar(message)

然后就看了官方给的某个示例源码(JetSnack)中的实现,结果诡异的事情出现了:

https://img1.sycdn.imooc.com//61c9f598000102c309100704.jpg

https://img1.sycdn.imooc.com//61c9f5990001f9e709480761.jpg

这里直接开了个协程,然后还单独写了一个SnackManager,里面维护了一个用于存放Message的List,Message是作者自己写的数据类,两个参数一个是UUID一个是要显示的文字的资源id。

如无必要,勿增实体的原则在编程中也是适用的,明明调用一个方法就能解决的问题,为什么这里要单独开一个类,还要维护一个List,甚至还用上了Flow?这显然是一个谜题。

最初的疑问是Message的id,但是看到后面的代码这个谜题很快解开了:

id的作用是区分不同的Message对象便于删除。

但是,如果是这样直接用hashCode不是更方便,有必要整一个UUID吗?这里依旧是谜题。

最大的一个疑问是,为什么要维护一个List?如果说想用Flow,直接把要显示的文字作为MutableStateFlow就好了,用了List结果还是取第一个元素,目的是什么?

过程我忘记的差不多了,直接说结论:

1.当collect块里面调用了挂起函数,在那个函数完成以前无论怎么更新数据都不会触发收集。

2.基于上面的原因,加上我直到今天才发现,scaffoldState.snackbarHostState.showSnackbar()是一个挂起函数,答案就显然易见了。

3.List是为了防止某些手贱的用户点的太快,导致SnackBar被吞。如果把要显示的内容作为StateFlow,在collect块挂起期间用户多次触发显示SnackBar的逻辑,就只会显示最后一次触发时的文字。我开始以为调用几次update就会触发几次collect,没有万恶的挂起函数是这样,但是一旦挂起,无论调用多少次update挂起结束时都只会触发一次collect并且数据以最后一次update为准。

那么问题又回到了最初,为什么非要用Flow把显示SnackBar这件事变得复杂呢?

还是忘记了过程,直接说答案:为了解耦。

试想一个场景,一个输入框要输入电话号码,如果用户点击确定时号码不足11位,那么此时要弹一个Toast。极其简单的场景,但是按照MVVM的原则,手机号码是数据,数据的持有者一定是ViewModel,而且检测号码是否合法的逻辑也应该写在ViewModel里面。

ViewModel肯定不能直接弹Toast,那么解决方案可以是提供一个回调,让UI那边来弹出。但这样还是有问题,这个逻辑还是在ViewModel里面调用的,而且Compose下这个方法不行,因为回调脱离了Compose的作用域,其次还有协程作用域之类的问题......

这个时候,直接让ViewModel根据号码是否合法去更新一个boolean变量,然后让UI根据这个变量来决定是否弹出就行了。虽然在ViewModel里面写一个检测是否合法的方法,让UI来调用也是一样,但是讲道理这部分逻辑应该是对UI完全屏蔽的。

回到原来的问题,其实就是因为这个源码里面弹出SnackBar的调用方是ViewModel,另外弹出Toast算一个公共的操作,所以提取到了StateHolder里面并以一种麻烦的方式实现了弹出。


谜题1解开了。





点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消