Android于2005年问世,在该平台存在的12年中,该平台取得了惊人的成功,成为安装次数最多的移动操作系统。 在此期间,已经发布了14种不同版本的操作系统,而Android一直在变得越来越成熟。 但是,平台的一个非常重要的领域仍然被忽略:一种标准的体系结构模式,能够处理平台的特殊性,并且足够普通开发人员理解和采用。
好吧,迟到总比没有好。 在上一个Google I / O上,Android团队最终决定解决此问题,并响应来自世界各地的开发人员的反馈,宣布了有关Android应用程序体系结构的官方建议,并提供了实现它的构建基块:新的体系结构组件。 而且更好的是,他们设法做到了这一点,而没有损害我们大家都知道和喜爱的系统的开放性。
在本教程中,我们将探索Android团队在Google I / O上提出的标准化架构,并研究新架构组件的主要元素: Lifecycle
, ViewModel
, LifeData
和Room
。 我们不会过多地关注代码,而是专注于这些主题背后的概念和逻辑。 我们还将介绍一些简单的代码段,所有代码段均使用Kotlin编写,Kotlin是一种出色的语言,目前已由Android正式支持。
1. Android缺少什么?
如果您只是作为开发者的旅程而去,那么您可能不知道我在说什么。 毕竟,应用架构最初可能是一个晦涩的主题。 但请相信我,您将很快了解其重要性! 随着应用程序的增长和变得越来越复杂,其体系结构将变得越来越重要。 从字面上看,它可以使您的工作如鱼得水,也可以成为生活的地狱。
应用架构
粗略地讲,应用程序体系结构是在开发过程开始之前需要制定的一致计划。 该计划提供了如何组织和组合不同应用程序组件的地图。 它提出了在开发过程中应遵循的准则,并做出了一些牺牲(通常与更多的类和样板有关),这些牺牲最终将帮助您构建一个可测试,可扩展和可维护的编写良好的应用程序。
软件应用程序体系结构是定义满足所有技术和运营要求的结构化解决方案的过程,同时优化了诸如性能,安全性和可管理性之类的通用质量属性。 它涉及基于一系列因素的一系列决策,并且每个决策都会对应用程序的质量,性能,可维护性和整体成功产生重大影响。
— Microsoft的软件体系结构和设计指南
好的体系结构要考虑很多因素,尤其是系统特性和限制。 有许多不同的体系结构解决方案,它们各有利弊。 但是,一些关键概念在所有愿景之间是相同的。
旧错误
直到上一次Google I / O为止,Android系统才建议使用任何特定的体系结构进行应用程序开发。 这意味着您完全可以自由采用任何模型:MVP,MVC,MVPP,甚至根本没有任何模式。 最重要的是,Android框架甚至没有提供针对系统本身(特别是组件的生命周期)所产生问题的本地解决方案。
因此,如果您想在应用程序上采用Model View Presenter模式,则需要从头开始提出自己的解决方案,编写大量样板代码,或者采用没有官方支持的库。 缺乏标准导致了许多编写不佳的应用程序,其代码库难以维护和测试。
正如我所说,这种情况已经受到批评多年。 实际上,我最近在我的Android系列文章“ 如何采用Model View Presenter”中写了关于此问题及其解决方法的文章。 但是重要的是,经过12年的努力,Android团队终于决定听取我们的投诉并为我们解决这个问题。
2. Android架构
新的《 Android体系结构指南》定义了优秀的Android应用程序应遵循的一些关键原则,并为开发人员创建安全的应用程序提供了安全的途径。 但是,指南明确指出所提供的路线不是强制性的,最终的决定是个人决定; 开发人员应该决定采用哪种类型的体系结构。
根据指南,一个好的Android应用程序应该将关注点牢固地分开,并从模型驱动UI。 任何不处理UI或操作系统交互的代码都不应放在“活动”或“片段”中,因为保持它们尽可能干净将使您避免许多与生命周期相关的问题。 毕竟,系统可以随时销毁“活动”或“碎片”。 另外,数据应由与UI隔离的模型处理,因此应与生命周期问题隔离。
推荐的新架构
在我们所知道的标准模式中,Android所推荐的体系结构无法轻易标记。 它看起来像“模型视图控制器”模式,但是与系统的体系结构紧密相关,以至于很难使用已知的约定来标记每个元素。 但是,这无关紧要,因为重要的是它依靠新的体系结构组件来创建关注点分离,并具有出色的可测试性和可维护性。 而且更好的是,它易于实现。
要了解Android团队的建议,我们必须了解架构组件的所有元素,因为它们将为我们带来繁重的工作。 有四个组件,每个组件都有特定的角色: Room
, ViewModel
, LiveData
和Lifecycle
。 所有这些部分都有各自的职责,并且它们一起工作以创建一个可靠的体系结构。 让我们看一下所建议体系结构的简化图,以更好地理解它。
如您所见,我们有三个主要元素,每个元素都有其责任。
-
Activity
和Fragment
代表View
层,它不涉及业务逻辑和复杂的操作。 它仅配置视图,处理用户交互,最重要的是,观察并展示从ViewModel
获取的LiveData
元素。 -
ViewModel
自动观察视图的Lifecycle
状态,在配置更改和其他Android生命周期事件期间保持一致性。 视图还要求从Repository
获取数据,该Repository
以可观察的LiveData
形式提供。 重要的是要了解ViewModel
永远不会直接引用View
,并且数据的更新始终由LiveData
实体完成。 -
Repository
不是一个特殊的Android组件。 这是一个简单的类,没有任何特定的实现,它负责从数据库到Web服务的所有可用源中获取数据。 它处理所有这些数据,通常将它们转换为可观察的LiveData
并使它们可用于ViewModel
。 -
Room
数据库是一个SQLite映射库,可简化处理数据库的过程。 它会自动编写大量样板文件,在编译时检查错误,最重要的是,它可以直接返回可观察到的LiveData
查询。
我相信您已经注意到我们已经谈论了很多关于可观察物的话题。 观察者模式是LiveData
元素和Lifecycle
感知组件的基础之一。 此模式允许对象将其状态或数据的任何更改通知观察者列表。 因此,当活动观察到LiveData
实体时,当该数据经过任何类型的修改时,它将接收更新。
3.体系结构组件
我们必须深入研究新组件的各个方面,才能真正理解和采用这种架构模型。 但是,我们不会在本教程中介绍所有细节。 由于每个元素的复杂性,在本教程中,我们仅讨论每个元素背后的一般概念,并介绍一些简化的代码片段。 我们将尝试覆盖足够的范围以展示组件并开始您的入门。 但是不要担心,因为本系列的后续文章将深入探讨并涵盖架构组件的所有特殊性。
生命周期感知组件
大多数Android应用程序组件都有附加的生命周期,这些生命周期由系统本身直接管理。 直到最近,还是要由开发人员来监视组件的状态并采取相应的措施,以便在适当的时候初始化和结束任务。 但是,很容易混淆并犯与此类操作有关的错误。 但是android.arch.lifecycle
包改变了这一切。
现在,活动和片段具有连接到它们的Lifecycle
对象, LifecycleObserver
类可以观察到该对象,例如ViewModel
或实现此接口的任何对象。 这意味着观察者将收到有关它正在观察的对象的状态变化的更新,例如Activity暂停或开始时。 它还可以检查观察对象的当前状态。 因此,现在处理必须考虑框架生命周期的操作要容易得多。
现在,要创建符合此新标准的Activity
或Fragment
,您必须扩展LifecycleActivity
或LifecycleFragment
。 但是,由于Android团队的目标是将这些新工具与其框架完全集成在一起,因此不一定总是需要这样做。
class MainActivity : LifecycleActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
LifecycleObserver
接收Lifecycle
事件,并可以通过注释做出反应。 不需要方法重写。
class MainActivityObserver : LifecycleObserver, AnkoLogger {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
info("onResume")
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
info("onPause")
}
}
LiveData
组件
LiveData
组件是一个数据持有人,其中包含可以观察到的值。 假定观察者在LiveData
实例化期间提供了Lifecycle
,则LiveData
将根据Lifecycle
状态运行。 如果观察者的Lifecycle
状态为STARTED
或RESUMED
,则观察者active
;否则,观察者active
。 否则,它是inactive
。
LiveData
知道何时更改数据以及观察者是否active
并且应该接收更新。 LiveData
另一个有趣特征是,如果它处于Lifecycle.State.DESTROYED
状态,则能够删除观察者,从而避免了通过Activity和Fragment观察时发生内存泄漏。
LiveData
必须实现onActive
和onInactive
方法。
class LocationLiveData(context: Context)
: LiveData<Location>(), AnkoLogger, LocationListener {
private val locationManager: LocationManager =
context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
override fun onActive() {
info("onActive")
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, this)
}
override fun onInactive() {
info("onInactive")
locationManager.removeUpdates(this)
}
// ....
}
要观察LiveData
组件,必须调用observer(LifecycleOwner, Observer<T>)
。
class MainActivity : LifecycleActivity(), AnkoLogger {
fun observeLocation() {
val location = LocationLiveData(this)
location.observe(this,
Observer { location ->
info("location: $location")
})
}
}
ViewModel
组件
ViewModel
是新的体系结构组件中最重要的类之一,它被设计为保存与UI相关的数据,并在诸如屏幕旋转之类的配置更改期间保持其完整性。 ViewModel
能够与Repository
进行对话, LiveData
获取LiveData
并使它依次可用,以供视图观察。 配置更改后, ViewModel
也不需要对Repository
进行新调用,这可以极大地优化代码。
要创建视图模型,请扩展ViewModel
类。
class MainActivityViewModel : ViewModel() {
private var notes: MutableLiveData<List<String>>? = null
fun getNotes(): LiveData<List<String>> {
if (notes == null) {
notes = MutableLiveData<List<String>>()
loadNotes()
}
return notes!!
}
private fun loadNotes() {
// do async operation to fetch notes
}
}
要从视图访问,可以调用ViewProviders.of(Activity|Fragment).get(ViewModel::class)
。 此工厂方法将根据需要返回ViewModel
的新实例或获取保留的实例。
class MainActivity : LifecycleActivity(), AnkoLogger {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewModel = ViewModelProviders.of(this)
.get(MainActivityViewModel::class.java)
viewModel.getNotes().observe(
this, Observer {
notes -> info("notes: $notes")
}
)
}
}
Room
组件
从一开始,Android就支持SQLite。 但是,要使其工作,总是有必要写很多样板。 另外,SQLite不会保存POJO(普通的Java对象),并且不会在编译时检查查询。 随之而来的是Room
解决这些问题! 它是一个SQLite映射库,能够持久存储Java POJO,将查询直接转换为对象,在编译时检查错误以及从查询结果生成LiveData
可观察对象。 Room
是一个对象关系映射库,其中包含一些很棒的Android功能。
到目前为止,您可以完成Room
能够使用其他ORM Android库的大部分功能。 但是,它们都没有得到官方支持,最重要的是,它们不能产生LifeData
结果。 Room
库非常适合作为拟议的Android体系结构上的持久层。
要创建Room
数据库,您需要一个@Entity
来持久化(可以是任何Java POJO),一个@Dao
接口来进行查询和输入/输出操作,以及一个@Database
抽象类,该抽象类必须扩展RoomDatabase
。
@Entity
class Note {
@PrimaryKey
var id: Long? = null
var text: String? = null
var date: Long? = null
}
@Dao
interface NoteDAO {
@Insert( onConflict = OnConflictStrategy.REPLACE )
fun insertNote(note: Note): Long
@Update( onConflict = OnConflictStrategy.REPLACE )
fun updateNote(note: Note): Int
@Delete
fun deleteNote(note: Note): Int
@Query("SELECT * FROM note")
fun findAllNotes(): LiveData<Note>
// on Kotlin the query arguments are renamed
// to arg[N], being N the argument number.
// on Java the arguments assume its original name
@Query("SELECT * FROM note WHERE id = :arg0")
fun findNoteById(id: Long): LiveData<Note>
}
@Database( entities = arrayOf(Note::class), version = 1)
abstract class Databse : RoomDatabase() {
abstract fun noteDAO(): NoteDAO
}
向您的项目添加架构组件
目前,要使用新的架构组件,您需要先将Google存储库添加到build.gradle
文件中。 有关更多详细信息,请参见官方指南 。
allprojects {
repositories {
jcenter()
// Add Google repository
maven { url 'https://maven.google.com' }
}
}
结论
如您所见,Android提出的标准化架构涉及很多概念。 不要期望对此主题有完整的了解。 毕竟,我们只是在介绍主题。 但是您现在肯定已经掌握了足够的知识,可以理解体系结构背后的逻辑以及不同体系结构组件的角色。
我们讨论了与拟议的Android架构及其组件相关的大多数主题; 但是,有关组件实现的详细信息和某些其他功能(如Repository
类和Dagger 2系统)不会在第一部分中介绍。 我们将在下一篇文章中探讨这些主题。
再见!
翻译自: https://code.tutsplus.com/tutorials/introduction-to-android-architecture--cms-28749