Android架构组件简介

作者: Android征途 | 来源:发表于2019-02-18 16:47 被阅读18次

    Android在2005年被引入世界,在这12年的存在中,该平台取得了惊人的成功,成为安装最多的移动操作系统。在此期间,已经推出了14个不同版本的操作系统,Android总是变得更加成熟。然而,平台的一个非常重要的领域仍然被忽略:标准的架构模式,能够处理平台特性,并且足够简单,以便普通开发人员理解和采用。

    好吧,迟到总比没有好。在最后的Google I / O中,Android团队最终决定解决这个问题并回应来自世界各地的开发人员的反馈,宣布正式推荐Android应用程序架构并提供实现它的构建块:新架构组件。更好的是,他们设法做到了这一点,同时又没有损害我们都知道和喜爱的系统的开放性。

    架构组件

    在本教程中,我们将探讨由Android团队在谷歌I / O提出的标准化体系结构,并期待在新的体系结构组件的主要元素: LifecycleViewModelLifeData,和Room。我们不会过多关注代码,而是关注这些主题背后的概念和逻辑。我们还将看一些简单的片段,所有片段都是用Kotlin编写的,这是一种现在由Android正式支持的神奇语言。

    1. 什么是Android缺失?

    如果您刚刚开始作为开发人员的旅程,您可能无法确切地知道我在说什么。毕竟,应用程序架构起初可能是一个模糊的主题。但请相信我,你很快就会了解它的重要性!随着应用程序的增长和变得越来越复杂,其架构将变得越来越重要。它可以让你的作品成为幸福或生活地狱。

    应用架构

    粗略地说,应用程序体系结构是一个需要在开发过程开始之前制定的一致计划。该计划提供了如何组织和捆绑不同应用程序组件的映射。它提出了在开发过程中应遵循的准则,并强制做出一些牺牲(通常与更多类和样板相关),最终将帮助您构建一个更易于测试,可扩展和可维护的编写良好的应用程序。

    软件应用程序体系结构是定义满足所有技术和操作要求的结构化解决方案的过程,同时优化常见的质量属性,如性能,安全性和可管理性。它涉及基于各种因素的一系列决策,每个决策都会对应用程序的质量,性能,可维护性和整体成功产生相当大的影响。

    • Microsoft的软件架构和设计指南

    良好的架构需要考虑很多因素,尤其是系统特性和限制。有许多不同的建筑解决方案,所有这些都有利有弊。但是,一些关键概念在所有愿景之间都很常见。

    老错误

    在最后一个Google I / O之前,Android系统不建议任何特定的架构用于应用程序开发。这意味着你可以完全自由地采用任何模型:MVP,MVC,MVPP,甚至根本没有模式。最重要的是,Android框架甚至没有为系统本身创建的问题提供本机解决方案,特别是组件的生命周期。

    Google IO 2017的好消息

    因此,如果您想在应用程序上采用Model View Presenter模式,则需要从头开始提出自己的解决方案,编写大量样板代码,或者在没有官方支持的情况下采用库。缺乏标准会导致许多编写得很糟糕的应用程序,其代码库难以维护和测试。

    正如我所说,这种情况多年来一直受到批评。事实上,我最近写了一篇关于这个问题以及如何在我的如何在Android 系列上采用模型视图演示器来解决它的问题 。但重要的是,经过12年的漫长岁月,Android团队最终决定倾听我们的抱怨并帮助解决这个问题。

    2. Android架构

    新的Android体系结构指南定义了一个好的Android应用程序应该遵循的一些关键原则,并为开发人员提供了一个安全的途径来创建一个好的应用程序。但是,该指南明确指出所提出的路线不是强制性的,最终决定是个人的; 开发人员应该决定采用哪种类型的架构。

    根据该指南,一个好的Android应用程序应该提供一个牢固 的关注点分离, 并从一个模型驱动UI。任何不处理UI或操作系统交互的代码都不应该在Activity或Fragment中,因为尽可能保持它们干净将允许您避免许多与生命周期相关的问题。毕竟,系统可以随时销毁活动或碎片。此外,数据应由与UI隔离的模型处理,从而处理生命周期问题。

    新推荐的架构

    Android推荐的架构无法在我们所知的标准模式中轻松标注。它看起来像一个模型视图控制器模式,但它与系统的架构密切相关,很难使用已知的约定标记每个元素。但这并不重要,因为重要的是它依赖于新的架构组件来创建关注点分离,具有出色的可测试性和可维护性。而且更好的是,它很容易实现。

    要了解Android团队提出的建议,我们必须了解架构组件的所有元素,因为它们将为我们带来繁重的工作。有四个组成部分,每一个特定的角色: RoomViewModel,****LiveData,和Lifecycle。所有这些部分都有自己的责任,他们共同努力创建一个坚实的架构。让我们看一下拟议架构的简化图,以便更好地理解它。

    Android架构

    如您所见,我们有三个主要元素,每个元素都有其责任。

    1. ActivityFragment代表的View层,不与业务逻辑和复杂的操作处理。它只配置视图,处理用户交互,最重要的是,观察和展示 LiveData从中获取的元素 ViewModel
    2. ViewModel 自动观察Lifecycle的视图的状态下,维持期间配置更改和其他Android生命周期事件的一致性。视图还要求从中获取数据Repository,这是作为可观察的提供的 LiveData。重要的是要理解,ViewModel 从不View直接引用,并且数据的更新总是由LiveData实体完成。
    3. Repository不是一个特殊的Android组件。它是一个简单的类,没有任何特定的实现,它负责从所有可用的源,从数据库到Web服务获取数据。它处理所有这些数据,通常将它们转换为可观察数据 LiveData并使它们可用于ViewModel
    4. Room数据库是一个SQLite映射库,它有助于处理数据库。它会自动编写大量样板文件,在编译时检查错误,最重要的是,它可以直接返回带有observable的查询LiveData

    我相信你已经注意到我们已经谈了很多关于可观测量的东西。该Observer模式是的基地之一LiveData元素和Lifecycle感知组件。此模式允许对象通知观察者列表其状态或数据的任何更改。因此,当一个Activity观察一个LiveData实体时,它会在该数据经过任何修改时收到更新。

    另一个Android建议是使用依赖注入系统来巩固其架构,例如Google的Dagger 2 或使用服务定位器模式(这比DI更简单,但没有很多优点)。我们不会在本教程中介绍DI或服务定位器,但Envato Tuts +有一些关于这些主题的优秀教程。但是,请注意,使用Dagger 2和Android组件有一些特殊性,将在本系列的第二部分进行说明。

    3.架构组件

    我们必须深入研究新组件的各个方面,以便能够真正理解和采用这种架构模型。但是,我们不会深入了解本教程中的所有细节。由于每个元素的复杂性,在本教程中,我们只讨论每个元素背后的一般概念,并查看一些简化的代码片段。我们将尝试覆盖足够的空间来展示组件并让您入门。但不要害怕,因为本系列中的未来文章将深入挖掘并涵盖架构组件的所有特性。

    生命周期感知组件

    大多数Android应用程序组件都附加了生命周期,这些生命周期由系统本身直接管理。直到最近,开发人员才能监控组件的状态并采取相应的措施,在适当的时候初始化和结束任务。然而,很容易混淆并犯这种类型的操作相关的错误。但是这个[android.arch.lifecycle](https://developer.android.com/reference/android/arch/lifecycle/package-summary.html)包改变了这一切。

    现在,活动和片段有一个[Lifecycle](https://developer.android.com/reference/android/arch/lifecycle/Lifecycle.html)附加到它们的对象,可以通过[LifecycleObserver](https://developer.android.com/reference/android/arch/lifecycle/LifecycleObserver.html)类来观察,比如[ViewModel](https://developer.android.com/reference/android/arch/lifecycle/ViewModel.html)实现此接口的任何对象。这意味着观察者将收到有关其正在观察的对象的状态更改的更新,例如暂停活动或何时启动。它还可以检查被观察对象的当前状态。因此,现在处理必须考虑框架生命周期的操作要容易得多。

    LifecycleObserver对LifecycleEvents做出反应

    现在,创建一个ActivityFragment符合这一新标准,你要扩展LifecycleActivityLifecycleFragment。但是,这可能并不总是必要的,因为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组件是一个数据持有者,包含可以观察到的值。鉴于观察者LifecycleLiveData实例化期间提供了一个,LiveData将根据Lifecycle状态行事。如果观察者的 Lifecycle 状态是 STARTED 或者 RESUMED,观察者是active; 否则就是inactive

    LiveData 知道数据何时被更改,以及观察者是否active应该接收更新。另一个有趣的特性LiveData是它能够在观察者处于某种Lifecycle.State.DESTROYED 状态时将其移除,从而避免在活动和碎片观察时发生内存泄漏。

    LiveData值更新过程

    一个LiveData必须实现 onActiveonInactive方法。

    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从它并使它又可以通过视图来观察。ViewModel也不需要对Repositoryafter配置更改进行新调用,这会对代码进行大量优化。

    ViewModel对UI生命周期很紧张

    要创建视图模型,请扩展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](https://maven.google.com/)' }`
    
    `}`
    
    `}`
    
    

    结论

    如您所见,Android提出的标准化架构涉及很多概念。不要期望对这个主题有一个完整的了解。毕竟,我们只是介绍主题。但是你现在已经掌握了足够的知识来理解架构背后的逻辑以及不同架构组件的角色。

    我们讨论了与提议的Android架构及其组件相关的大多数主题; 但是,Repository第一部分不能涵盖有关组件实现和一些额外内容的详细信息,例如类和Dagger 2系统。我们将在下一篇文章中探讨这些主题。
    再见!

    想学习更多Android知识,或者获取相关资料请加入Android技术开发交流2群:935654177。本群可免费获取Gradle,RxJava,小程序,Hybrid,移动架构,NDK,React Native,性能优化等技术教程!

    相关文章

      网友评论

        本文标题:Android架构组件简介

        本文链接:https://www.haomeiwen.com/subject/ykxzeqtx.html