MVC
由于在 Android 中 xml 布局的功能性太弱,所以 Activity 承担了绝大部分的工作.
总结:
- 具有一定的分层,model 解耦,controller 和 view 并没有解耦
- controller 和 view 在 Android 中无法做到彻底分离,Controller 变得臃肿不堪
- 易于理解、开发速度快、可维护性高
MVP
Android MVP 快速集成框架
通过引入接口 BaseView,让相应的视图组件如 Activity,Fragment去实现 BaseView,把业务逻辑放在 presenter 层中,弱化 Model 只有跟 view 相关的操作都由 View 层去完成。
总结:
- 彻底解决了 MVC 中 View 和 Controller 傻傻分不清楚的问题
- 但是随着业务逻辑的增加,一个页面可能会非常复杂,UI 的改变是非常多,会有非常多的 case,这样就会造成 View 的接口会很庞大
- 更容易单元测试
MVVM-Jetpack
在 MVP 中 View 和 Presenter 要相互持有,方便调用对方,而在 MVP 中 View 和 ViewModel 通过 Binding 进行关联,他们之前的关联处理通过 DataBinding 完成。
总结:
- 很好的解决了 MVC 和 MVP 的问题
- 视图状态较多,ViewModel 的构建和维护的成本都会比较高
- 但是由于数据和视图的双向绑定,导致出现问题时不太好定位来源
Navigation
即学即用Android Jetpack - Navigation
Android官方架构组件Navigation:大巧不工的Fragment管理框架
Android Jetpack 导航组件 | Android 中文教学视频
Data Binding
即学即用Android Jetpack - Data Binding
ViewModelsa & LiveData
[Android Jetpack - ViewModel | 中文教学视频](https://www.bilibili.com/video/av29949898) |
[Android Jetpack: LiveData 和 Lifecycle 介绍 | 中文教学视频](https://www.bilibili.com/video/av29949898) |
即学即用Android Jetpack - ViewModel & LiveData
Lifecycle
Room
[Android Jetpack Room | 中文教学视频](https://www.bilibili.com/video/av30617550) |
Paging
[Android Jetpack: 分页库 (Paging Library) | 中文教学视频](https://www.bilibili.com/video/av35089294) |
WorkManger
即学即用Android Jetpack - WorkManger
[Android Jetpack WorkManager | Android 中文教学视频](https://www.bilibili.com/video/av56276889) |
Jetpack
架构
使用示例
使用示例是Google的官方示例SunFlower
build.gradle
android {
···
dataBinding {
enabled = true
}
}
dependencies {
···
implementation "androidx.fragment:fragment-ktx:$rootProject.fragmentVersion"
implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$rootProject.lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycleVersion"
}
fragment_plant_detail.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.google.samples.apps.sunflower.viewmodels.PlantDetailViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
···
android:text="@{viewModel.plant.name}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
PlantDetailFragment.kt
class PlantDetailFragment : Fragment() {
private val args: PlantDetailFragmentArgs by navArgs()
private lateinit var shareText: String
private val plantDetailViewModel: PlantDetailViewModel by viewModels {
InjectorUtils.providePlantDetailViewModelFactory(requireActivity(), args.plantId)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = DataBindingUtil.inflate<FragmentPlantDetailBinding>(
inflater, R.layout.fragment_plant_detail, container, false).apply {
viewModel = plantDetailViewModel
lifecycleOwner = this@PlantDetailFragment
}
plantDetailViewModel.plant.observe(this) { plant ->
// 更新相关 UI
}
return binding.root
}
}
Plant.kt
data class Plant (
val name: String
)
PlantDetailViewModel.kt
class PlantDetailViewModel(
plantRepository: PlantRepository,
private val plantId: String
) : ViewModel() {
val plant: LiveData<Plant>
override fun onCleared() {
super.onCleared()
viewModelScope.cancel()
}
init {
plant = plantRepository.getPlant(plantId)
}
}
PlantDetailViewModelFactory.kt
class PlantDetailViewModelFactory(
private val plantRepository: PlantRepository,
private val plantId: String
) : ViewModelProvider.NewInstanceFactory() {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return PlantDetailViewModel(plantRepository, plantId) as T
}
}
InjectorUtils.kt
object InjectorUtils {
private fun getPlantRepository(context: Context): PlantRepository {
···
}
fun providePlantDetailViewModelFactory(
context: Context,
plantId: String
): PlantDetailViewModelFactory {
return PlantDetailViewModelFactory(getPlantRepository(context), plantId)
}
}