前言
开发android也半年有余了,前面一直边开发android, 边学习android各种库
对于android框架上分层的开发并不是很关注,并没有想得很清楚。
有时候较真的时候,也不知道代码写的是不是在框架的层次上看有没有问题,糊里糊涂的。特地花了两个小时总结了下android开发规范。
框架结构
引用一张Android框架图:
Activity层分析
Activity和对应的activity.xml作为UI层,最大的职责就是显示UI和操作UI界面
Activity继承于context,可以方便的操作UI资源
Activity具备生命周期
Activity可以结合databinding来简化model和
总结
1. UI最大的职责是处理UI逻辑,当中的数据操作,和逻辑最好剥离到viewmodel中运行
2. UI可能持有多个viewmodel,每个viewmodel之间的数据和应该是尽可能不关联
3. UI只负责和ViewModel进行交互。
交互的形式为:
1. 监听ViewModel的LiveData的数据变化,然后UI对数据的变化做出相应的UI变化
2. 调用ViewModel的接口,ViewModel接口根据逻辑修改数据, UI对数据做出相应的UI变化
1. LiveData基本原理
livedata在onStart之后才会激活, onDestroy时就会移除观察者。
整理和发散:
1. 在onStart之前,liveData先注册观察者,liveData后被setValue时,观察者会工作。
2. liveData注册观察者之前,livedata有值,注册观察者,观察者会被触发一次。
3. 在onStart之前,当liveData被setValue时,liveData后注册观察者,观察者在onStart触发时会工作。
4. Livedata的工作周期时[onStart-onStop]
5. onDestroy之后,LiveData和Activity就解除绑定,Activity可以被回收了。
6. onStart状态会多次发生, 如果在onStart中注册观察者,
总结:
1. 因为[onStart-onStop]之间的状态会多次发生,所以应该在onCreate进行监听,在onStart监听会可能会监听(onStart状态发生的次数)N次,触发N次。
2. liveData先赋值和livedata先注册观察者的顺序影响不大,唯一关心的是监听之前赋值多次只能处理最后一次
RxBus监听(RxJava)
RxBus作为消息总线,负责消息接收和分发
整理和发散
1. RxBus最好能够绑定生命周期来自动unregister,生命周期又掌管在Activity/Fragment手中,
所以一般来说应该在Activity/Fragment中进行rxbus的监听
但是业务逻辑和数据处理应该尽可能地在viewmodel中处理,
所以其实应该在viewmodel中进行监听操作
而Activity/Fragment就老老实实只处理UI逻辑就可以了。
那么如何做到这一步呢?
实现一个自带生命周期的BaseViewModel
然后通过activity的lifecycle.addObserver来给BaseViewModel添加生命周期
然后再参考RxAppCompatActivity(第三方库)实现LifecycleProvider(三方库)生命周期机制
这样viewModel便可以心安理得使用rxbus来响应消息。
总结
1. 应该在viewmodel中监听消息
2. 有了BaseViewModel,ViewModel更彻底地和Activity进行了剥离。Activity回收后,自然而然会清除生命周期的观察者baseviewmodel,baseviewmodel也完全没有持有任何activity的实例。清晰度max!!!
3. rxjava绑定生命周期的机制可以自定义[onCreate-onDestroy],或者[onResume-onPause],灵活度很高。viewModel有时候就是只需要在[onResume-onPause]进行监听即可。也有时候要在[onStart-onStop] (熄屏状态)的时候监听来自后台Service的消息。
viewmodel层分析
viewmodel生命周期长,适合保存数据
支持viewModelScope管理协程(自动回收)
baseviewmodel可以自带生命周期(自己实现, 在activity中使用addObserver注册生命周期)
viewmodel回收时会调用onCleared
viewmodel层的职责是负责数据获取和逻辑的处理
思考
viewmodel对数据进行提炼和逻辑处理,和repository提供的model不一定相同。
按道理viewmodel应该定义UI更加方便处理的Model。
但是如果使用databinding,将viewmodel作为数据,那么viewmodel本身就是model
因此使用databinding,viewmodel层就可以省略model了。
因为有的人在viewmodel中,直接涉及了UI的操作,譬如使用了LiveData<Drawable>之类的值,
导致viewmodel和UI的业务逻辑产生了耦合(代码逻辑没有耦合),因此刚开始我摒弃了databinding的使用
现在回想应该是使用者使用出错,而不是不应该使用databinding。
总结
1. viewmodel层仅通过livedata,和activity进行被动的交互
2. viewmodel可以在init时使用异步进行初始化操作
3. viewmodel层向下只会和repository打交道
4. viewmodel自带生命周期监听,支持生命周期和RxBus绑定
5. viewmodel生命周期超长,如果用于保存数据,则不用关心saveInstance
6. viewmodel可以使用viewModelScope来进行协程管理
7. viewmodel可以对耗时的数据请求可以使用协程处理
8. viewmodel应该使用依赖注入,注入repository,这样方便进行测试,因此hilt/dragger必不可少
9. viewModel 同步初始化会卡住UI线程,不推荐,除非是某些参数实时性要求极高
Repository
数据的来源
数据可能来源于本地数据库
数据可能来源于远程服务
数据可能来源于sharedpreferences
数据可能来源于jni库
数据可能来源于模拟数据
repository屏蔽了数据来源的差异
总结
1. repository层提供的数据会比较复杂,甚至可能有多个数据获取,然后简单拼接的情况。
因此repository一定要定义自己的model。
2. repository是最好的假数据接入层,可以设计专门提供假数据的repository
3. repository又可以使用junit单元测试进行测试,测试数据可靠性。
4. repository层和设备深度绑定,隔离了repository层,viewmodel+假数据repository+ui就可以
方便的在模拟器中运行,查看效果了。(嵌入式领域)