前言
这个系列将讲述使用MVVM架构、LiveData、Room、Kodein、Retrofit、EventBus来建立一个统一的、优雅的、可维护的TODO程序,本系列分为多个章节,从0开始一步一步引入这些优秀的库。下图展示的是Jetpack组件库包含的内容,这套的架构方案的核心就是谷歌现在大力推荐的Jetpack作为基础,搭配外围脚手架补齐Jetpack短板,还原原汁原味的优雅Android。
多说一句,确保团队对架构有统一的理解是非常必要的,就好比开团要切adc一样自然,如此不论是bug修复还是功能开发都无需抽丝剥茧就能直接定位完成任务。
目录
• MVVM架构 - MVVM与单向数据流
• LiveData - 使用ViewModel绑定UI和点击事件
• EventBus - 全局事件分发
• Room - 丝滑的sqlite访问
• Retrofit - 丝滑的api接入
• Kodein - 引入依赖注入优雅生成ViewModel
• Service - 使用eventbus包装与service的通信
• Receiver和定时任务 - 安装卸载事件 各种manager的处理
• 低内存 - 组件被回收的正确处理
• Navigation - 优雅的Single Activity导航组件
• Paging - 分页组件
复制代码
本系列我们以构建一个TODO APP为例,逐步分析这些这套架构是如何发挥作用的。首先看看Android开发者官网上的MVVM架构图。
这里强调一点,使架构干净整洁的精髓就是保持数据流单向流动。
• Activity / Fragment
View层,在这一层里,不要放和业务逻辑相关的任何代码,只编写处理UI逻辑的代码和函数,供ViewModel调用。当然,ViewModel是不能直接调用activity的,否则就破坏了单项数据流了,这里可以使用接口的方式把activity中的方法传入viewModel,当然更好的方式是使用EventBus进行事件分发。
• ViewModel
保存UI相关的变量,可以与layout中的元素进行单向或双向的数据绑定。响应元素的onlick等事件,调用Repository完成任务,更改UI属性值,调用传入的回调接口或向eventbus发送事件来反馈用户操作是成功还是失败。ViewModel可以被多个Activity共享。
• Repository
对多个数据源的统一封装,形成统一方法,比如有saveUser(user: User)方法,内部调用远程api接口保存成功后,写入本地数据库,函数成功返回,但对调用者来说抽象了数据源的实现方法,减少上层逻辑处理负担。
• Model / Local Data Source
本地数据源抽象层
• Remote Data Source
远程数据源抽象层
复制代码
但是,我们的应用一般不可能这么简单,还会应用到service、receiver、后台进程什么的,这里为了简单起来,先不加入,等到后面对应的章节再补充进去。
起步
说了这么多废话,动手创建工程吧
工程创建
首先常规操作,创建一个名叫todo的工程
在module的build.gradle中加入
android {
...
dataBinding {
enabled = true
}
}
dependencies {
...
// architectures
implementation"androidx.lifecycle:lifecycle-viewmodel-ktx:$archLifecycleVersion"
implementation"androidx.lifecycle:lifecycle-livedata-ktx:$archLifecycleVersion"
implementation"androidx.lifecycle:lifecycle-extensions:$archLifecycleVersion"
}
复制代码
在project的build.gardle文件中统一声明版本
ext{
archLifecycleVersion='2.2.0'
}
复制代码
ViewModel创建
好了,一切就绪,我们首先建立我们的viewmodel,并声明一个hello字段,LiveData是个抽象类,我们使用MutableLiveData建立一个private的实例对象,并将其赋值给hello暴露给外部。
这里hello我们给个默认值"hello",该值可空,默认为null
class MainViewModel: ViewModel() {
val _hello = MutableLiveData("hello")
val hello : LiveData = _hello
}
复制代码
在layout中绑定ViewModel
接下来修改layout文件,打开默认创建的layout文件,将其用layout标签包裹并加入data块,声明变量名为viewmodel,变量类型是刚才创建的class。viewmodel建议全小写,可以在activity中定义的viewModel区别开。
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
name="viewmodel"
type="xyz.yuanxiaoqing.todo.MainViewModel" />
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewmodel.hello}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
复制代码
在textview中我们使用@{}语法将其单向绑定到hello变量上
MainActivity
好了,最后一步,将viewmodel实例化绑定到layout中。这里直接实例化了MainViewModel,仅作为演示,后面章节将介绍如何优雅生成这个对象。这个ActivityMainBinding是什么?他是Android Studio自动根据R.layout.activity_main生成的Binding对象。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding =
DataBindingUtil.setContentView(this, R.layout.activity_main)
val viewModel = MainViewModel()
binding.apply {
viewmodel = viewModel
}
}
}
复制代码
ok,成功绑定。