2023年Android开发者路线-第1部分[1]
2023年Android开发者路线-第2部分[2]
2023年Android开发者路线-第3部分[3]
2023年Android开发者路线-第4部分[4]
在上一篇博文中,我们讨论了现代 Android 开发的基本要素,包括 Fragments、App Navigation、Architecture Components 和 Android Jetpack 库。 在第4部分,我们将学习Android以下几个部分内容:
- 1. Design Patterns 设计模式
- 2. Architecture 架构
- 3. Asynchronous 异步
- 4. Network 网络
- 5. Image Loading 图片加载
- 6. Local Storage 本地存储
Design Patterns
软件设计模式是一种可重用的解决方案,用于解决软件工程中重复出现的、常见的软件问题。设计模式可以根据它们解决的问题类型进行分类,例如创建模式、行为模式和并发模式。
在Android开发中,经常会用到一些设计模式来解决Android平台常见的问题,管理资源的生命周期,比如Dependency Injection和Observer模式。
您可能已经至少使用过一次创建模式,例如Builder 模式、Factory 方法模式和Singleton 模式在 Android 开发中创建实例。
在本节中,您将探索影响现代 Android 开发中整体架构设计的三种主要模式。
依赖注入
依赖注入是现代 Android 开发中最流行的模式之一,它将创建对象的义务转移到类之外。
通过转移创建对象的义务,类之间不需要相互依赖。因此,您可以设计类之间松散耦合的依赖关系。
如果您正确使用依赖注入,您可以受益于以下优势:
- • 减少样板代码。
- • 类之间的松散耦合,因此您可以轻松编写单元测试。
- • 利用类的可重用性。
- • 提高代码的可维护性。
您可以按照手动依赖注入指南手动实施依赖注入,但强烈建议使用以下高效解决方案:Hilt、Dagger和Koin(严格的服务定位器模式)。
- •
Hilt
:Hilt 是 Android 的编译时依赖注入工具,它在Dagger之上运行。与Dagger-Android库相比,Hilt 生成标准的 Android Dagger 组件并减少了所需的样板代码量。此外,Google 提供与ViewModel、 Jetpack Compose、 Navigation和WorkManager的兼容性,在撰写本文时,它是现代 Android 开发强烈推荐的依赖注入工具。有关详细信息,请查看Hilt文档中的依赖项注入。 - •
Dagger
:Dagger 也是一种编译时依赖注入工具,基于javax.inject注释和 ( JSR 330 )。你可以使用 Dagger 为你的 Android 项目配置依赖注入,但是这将需要大量额外的设置成本,因为 Dagger 不是一个 Android 依赖库。强烈建议使用Hilt或Dagger-Android来大幅降低设置成本。 - •
Koin
:Koin 也是Kotlin 项目中流行的依赖注入(严格来说是服务定位器模式)工具,它易于使用且设置成本低。有关更多信息,请查看insert-koin.io。
更多依赖注入的内容参考:https://developer.android.com/training/dependency-injection
观察者模式
观察者模式是一种行为设计模式,允许您构建订阅机制以自动通知观察者任何状态更改。
观察者模式也是 Android 开发中最常用的模式之一,用于在组件之间构建松散耦合的架构。它还可用于克服 Android 平台限制,例如独立 Android 组件之间的通信。
您可以实现自己的订阅功能,并且可以通过以下库轻松使用它们:RxKotlin、Kotlin Flows和LiveData。
- • LiveData:LiveData 是一种生命周期感知、线程安全和数据持有者观察者模式。LiveData 的观察者与Android Lifecycles绑定,所以你不需要手动取消订阅你的观察者,当生命周期未激活时,他们不会订阅数据发射。因此,它将防止无法预测和难以识别的内存泄漏。它还通过LiveData-ktx库提供有用的操作符,并支持数据绑定和Room兼容性。然而,现代 Android 开发更喜欢 Kotlin 的 Flows 而不是 LiveData,因为协程已被广泛采用。如果您有兴趣迁移到 Flow,请查看从 LiveData 迁移到 Kotlin 的 Flow.
- • Kotlin Flows:Flows 是一种异步解决方案,它是冷流,类似于使用Coroutines 的序列。它们是异步和非阻塞的解决方案,在 Kotlin 的语言级别得到支持。Flows 还提供了有用的运算符,例如Transform operator、 Flattening operators和flowOn operator。您可以利用Android 中的StateFlow和SharedFlow来实现状态持有者可观察流并将值发送给多个消费者。
- • RxKotlin (RxJava):RxKotlin 起源于ReactiveX,是观察者模式、迭代器模式和函数式编程的结合。RxKotlin 提供了许多有用的运算符,允许您使用可观察序列来编写异步和基于事件的程序。此外,您可以使用这些运算符轻松解决并发问题,例如低级线程、同步和线程安全,并且有许多适用于 Android 的有用解决方案,例如RxAndroid。然而,RxKotlin 包含许多运算符,对于初学者来说可能过于复杂。Kotlin Flows或LiveData更易于使用,尤其是当您不需要在项目中使用大量复杂操作时。
存储库模式 存储库模式起源于领域驱动设计,这是一种通过提供数据抽象来调解领域和数据的软件方法。
表示层使用具有近似业务逻辑的接口的简单抽象,例如从本地数据库查询数据和从网络获取远程数据。实际的实现类执行繁重的工作并执行与领域相关的工作。
存储库在概念上封装了与特定域相关的可执行域函数的集合,并为其他层提供更多面向对象的方面。
在现代 Android 开发中,数据层由存储库组成,这些存储库作为公共接口暴露给其他层,并遵循单一真实来源原则。
因此其他层可以将域数据作为流来观察,例如 Kotlin 的Flow或LiveData,并保证真实的来源。有关存储库模式和数据层的更多信息,请查看App Architecture。
现在让我们讨论 App架构。
Architecture
架构是现代Android开发中至关重要的一部分,它决定了项目管理的整体代码复杂度和成本。
随着项目功能数量的增加,代码行数和代码内聚性也相应增加。应用程序架构广泛影响着项目的复杂性、可扩展性和鲁棒性,并使测试变得更加容易。通过定义每个层之间的边界,您可以清楚地定义它们的职责,并通过将它们模块化为专门的角色来分离每个职责。
在历史上,Android的架构趋势在过去几年中发生了变化,这取决于可用的解决方案和最佳实践。
七八年前,Android项目使用MVC和MVP架构模式构建,但现在大多数项目使用MVVM和MVI架构模式,因为引入了有用的订阅解决方案,如RxKotlin、Kotlin Flows和LiveData。
在本节中,您将了解近年来最流行的架构模式:MVVM、MVI和Clean Architecture。
MVVM
自从谷歌正式公布Architecture Components以来,MVVM(Model-View-ViewModel)是现代 Android 开发中最流行的架构设计之一,例如ViewModel、LiveData和Data Binding。
从历史上看,自从Microsoft 引入Model-View-ViewModel 模式以来,它已经被 WPF 开发人员使用了十多年。
MVVM 模式由View、ViewModel和Model组成,如下图所示:
每个组件在Android开发中都有不同的职责,定义如下:
- • View:负责构建用户界面,显示在屏幕上供用户看到。View由包括TextView、Button或Jetpack Compose UI等UI元素的Android组件组成。UI元素触发用户事件传递给ViewModel,并通过观察来自ViewModel的数据或UI状态来配置UI屏幕。理想情况下,View只包含代表屏幕和用户交互的UI逻辑,例如监听器,不包含业务逻辑。
- • ViewModel:这是一个独立的组件,不依赖于View,它保存来自Model的业务数据或UI状态,并将其传播到UI元素中。通常情况下,ViewModel和Model之间存在多个(一对多)关系,ViewModel将数据更改通知给View作为领域数据或UI状态。在现代Android开发中,谷歌建议使用ViewModel库,该库有助于开发人员轻松保存业务数据并在配置更改时保留状态。但从技术上讲,您可以说它与Microsoft的ViewModel不同,因为它与Microsoft的设计原意不太相似。为使其接近Microsoft的版本,您应该利用其他解决方案,如数据绑定和订阅机制解决方案,例如RxKotlin、Kotlin Flows和LiveData。有关更多详细信息,请查看Microsoft的“模型-视图-视图模型模式”。
- • Model:封装应用程序的领域/数据模型,通常包括业务逻辑、复杂的计算工作和验证逻辑。Model类通常与远程服务和本地数据库一起使用,这些库在库中封装了数据访问,如可执行领域函数的集合。仓库确保多个数据源的单一真相和整体应用程序数据的不变性。
如果您想探索使用MVVM架构和上述设计模式构建的开源项目,请查看GitHub上的Pokedex。
[MVVM开源项目Pokedex] https://github.com/skydoves/pokedex
MVI
MVI(Model-View-Intent)也是现代 Android 开发中流行的架构,因为Jetpack Compose将声明式编程带入了我们的生活。
MVI 模式侧重于单一事实源原则,为其他层提供不可变状态,以及表示用户操作和配置 UI 屏幕结果的状态的单向和不变性。
MVI 架构是基于 MVP 或 MVVM 等其他架构设计的状态管理机制,这意味着 MVI 架构可以根据你的设计在 Presenter 或 ViewModel 上运行。
与 MVVM 和 MVP 不同,MVI 的每个组件的定义略有不同:
- • Intent:Intent 是处理用户操作(UI 事件,如按钮单击事件)的接口和函数的定义。这些函数将 UI 事件转换为 Model 的接口并将结果传递给 Model 进行操作。顾名思义,我们可以说我们有意执行 Model 函数。
- • Model:在 MVI 中,Model 的定义与 MVP 和 MVVM 完全不同。在 MVI 中,Model 是一个功能机制,它接受来自 Intent 的输出并将其操作为可在 View 中呈现的 UI 状态。UI 状态是不可变的,并来自业务逻辑,它遵循单一真理源和单向数据流。
- • View:MVI 中的 View 具有与 MVP 和 MVVM 相同的职责,表示屏幕和用户交互,例如侦听器,并且不包含业务逻辑。与其他模式的实现最大的不同之一在于,MVI 确保单向数据流,因此 View 根据来自 Model 的 UI 状态呈现 UI 元素。
如果你对学习更多关于 MVI 的内容感兴趣,Hannes Dorfmann 的《使用模型-视图-意图进行响应式应用程序开发》一书将帮助你更好地掌握 MVI 架构。
如果你想探索一个使用 MVI 架构和上述设计模式构建的开源项目,请查看 GitHub 上的 WhatsApp Clone Compose。
Clean Architecture
Clean Architecture 是由 Robert C. Martin (Uncle Bob) 在他的 Clean 书系之一 “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” 中引入的,他提出了一些面向对象编程 (OOP) 范式的设计方法来构建强大且清晰的应用程序结构。
自从依赖注入解决方案(如 Dagger)和多模块项目环境被引入以来,Clean Architecture 在现代 Android 开发中被广泛使用。此外,该理论可以与其他架构一起使用,例如 MVP、MVVM 和 MVI。
这种架构带来以下优点:隔离模块、增加可重用性、提高可扩展性以及易于编写单元测试用例。但是,如果你正在开发一个不需要复杂业务逻辑的小项目,这种架构可能过于复杂,因此你应该调查一下这种架构是否对你的项目有优势。
在深入了解清洁架构理论之前,我们将讨论SOLID设计原则,这些原则是Uncle Bob在他的一系列干净书中介绍的。Robert提出了以下五个软件设计原则,使您可以构建易于理解、灵活和可维护的项目:
- • 单一职责:每个软件组件,如类或模块,应该只有一个更改的原因;这意味着在同一个组件、类或模块中设计不相关的功能会使代码的目的难以理解并且不清晰。
- • 开闭原则:您应该能够扩展组件的功能(开放性)而不破坏其点并且不修改使用(封闭性)。
- • 里氏替换:扩展类必须替换父类。这意味着父类必须具有提供简洁目的的最小接口,子类必须实现父类的每个抽象。
- • 接口隔离:正如您可以通过名称估算的那样,它是一种面向原子的原则,可以与单一职责和里氏替换原则相关联。最好创建许多较小的接口而不是一个巨大的接口,以防止功能臃肿并违反里氏替换原则。
- • 依赖反转:类和模块必须依赖于抽象,而不是具体实现,以实现单向和线性化的依赖性。此外,这确保了组件的纯净性,这意味着每个组件负责其专用角色。不要将其与依赖注入设计模式混淆。
清洁架构基本上遵循上述SOLID设计原则。Uncle Bob将清洁架构描述如下图所示:
圆心是最纯粹的范围,没有依赖于其他层。每个层必须暴露抽象以供外部层使用,这些外部层具有内部圆形依赖关系。正如您可能已经注意到的那样,这是 SOLID 设计原则的最大化组合。
每个层都有自己的单一职责,并遵循它们之间的依赖反转原则。现在让我们看看每个层的职责:
- • 实体:封装应用程序的一组业务规则和对象。该层还遵循最高级别的规则,并公开抽象以供其他层轻松使用。在 Google 的官方架构指南中,您可以将实体层视为数据层。
- • 用例:用例包含应用程序业务规则的定义,例如将在实体层中触发功能的用户操作。该层仅依赖于实体层,并向外部层公开抽象以执行特定于应用程序的业务逻辑。
- • 展示者(接口适配器):该层执行所有暴露的接口,这些接口是来自用例层的应用程序业务规则的定义,并与 UI 层通信。在 MVVM 中,ViewModel 属于此处。
- • UI(框架和驱动程序):UI 层表示 UI 如何呈现,包括 Activity、Fragment 和所有 UI 元素,例如用于 Android 屏幕上的 Android 部件。
如果您想了解更多关于这个概念并在您的Android项目中使用它,可以参考以下资料:
《The Clean Architecture》https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
《Architecting Android…The clean way?》https://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/
《Clean Architecture Tutorial for Android: Getting Started》https://www.raywenderlich.com/3595916-clean-architecture-tutorial-for-android-getting-started
Asynchronous
Asynchronous and Concurrency
在Android中,系统会创建一个主线程(也称为UI线程),负责处理应用程序的所有与UI相关的工作。主线程负责渲染UI元素、将事件分派给适当的用户界面以及Android UI工具包组件之间的所有交互。
因此,如果你想执行I/O或耗费大量计算工作(如网络请求和查询数据库),你应该在另一个线程(所谓的工作线程)中处理它们。这确保了主线程专注于渲染屏幕和处理用户交互。
话虽如此,编写一个高度多线程的程序很难维护和调试,还有其他考虑因素,如避免竞态条件和管理资源。幸运的是,有解决方案可以执行计算密集型的业务工作而不会阻塞主线程,并且它们使得不需要手动逐个处理每个线程成为可能。
现在让我们看看如何使用以下解决方案执行业务逻辑。
RxJava/RxKotlin
使用RxJava的优点之一是,它可以轻松地控制多线程问题,比如在后台线程中执行业务逻辑并在UI线程中获取结果。
RxJava提供了一个线程池,称为Schedulers,并且该线程池包含以下不同类型的线程:io、computation、single或者你可以创建一个全新的线程。
你可以通过使用SubscribeOn和ObserveOn运算符来指定Schedulers来操纵线程行为,这些运算符定义了哪个线程应该工作,哪个线程应该消耗结果。
如果你想了解更多关于RxJava和多线程的知识,可以参考Aritra Roy的《Multi-Threading Like a Boss in Android With RxJava 2》。
Coroutines
Coroutines是一种在语言级别上异步执行代码的优秀并发解决方案。
与线程不同,协程是纯粹的用户级语言抽象,因此它不直接绑定于操作系统资源,每个协程对象都在JVM堆中分配。这意味着协程由用户控制,消耗的资源更少,上下文切换的成本比线程低。
根据Android文档,协程很轻量级,因此您可以在单个线程上运行多个协程,并且因为它们基于作用域工作,所以导致的内存泄漏较少。Google还支持许多Jetpack库的集成和兼容性,例如ViewModelScope和LifecycleScope,如果您选择协程作为并发解决方案,您将获得许多优势。
如果您想了解有关Android的协程的更多信息,请查看《Kotlin协程在Android上》。
Network
网络通信是现代应用的重要组成部分。然而,构建自己的网络解决方案需要大量资源,如连接池、响应缓存、HTTP(超文本传输协议)特定功能、拦截器和异步调用支持。
7到8年前,Android开发人员使用HttpURLConnection或Apache的HttpClient执行HTTP请求。然而,这些库需要大量样板代码,并且不支持Android平台的兼容性,如连接特性、安全支持和DNS(域名系统)解析。
在本节中,我们将探讨Android最受欢迎的HTTP库:OkHttp和Retrofit。
OkHttp
OkHttp是由Square开发的HTTP客户端,为JVM和Android构建,并使用内部的现代I/O库Okio。它默认情况下可以高效地工作,帮助你快速建立HTTP客户端。当网络有问题(如连接问题)时,它有自己的恢复系统,所以你不需要手动处理。该库提供了现代的TLS(传输层安全)功能、Android的安全支持、缓存和拦截器。
OkHttp中最有能力的功能之一是拦截器,它是一个强大的机制,允许你记录、监视、修改、重写和重试调用。
你可以根据需要轻松地转换所有网络请求,例如在头部添加访问令牌(例如 Bearer 认证)或将 Gzip 压缩添加到请求正文中。
Retrofit
Retrofit 是一个类型安全的 HTTP 客户端,适用于 Android 和 JVM,也是由 Square 开发的。Retrofit 在 OkHttp 之上提供了抽象层,允许您轻松、简洁地定义请求规范,无需处理底层实现。
您还可以通过支持 Retrofit 注释构建所需的 HTTP 请求,包括 URL、标头操作、请求方法和正文。此外,通过附加可插拔的 Converter.Factory,您可以轻松地序列化所有 JSON 响应,而无需编写样板代码。
您还可以通过附加 CallAdapter 来操纵网络响应,这使您可以处理原始响应并将响应类型建模为所需的类型。有关更多信息,请查看 Modeling Retrofit Responses With Sealed Classes and Coroutines。
如果您想了解更多关于 Retrofit 的信息,请参阅 Retrofit 的官方页面。
Image Loading
图片加载也是现代应用程序开发的重要组成部分,例如当从网络加载用户资料或其他内容时。
您可以实现自己的图像加载系统,但它需要许多功能,在幕后下载图像,调整大小,缓存,渲染和内存管理等等。
在本节中,我们将探讨流行的 Android 图像库。
Glide
Glide 是由 bumptech 开发的最流行的图像库之一,并已经流行了很长一段时间。它已被许多全球产品和开源项目使用,包括 Google 的官方开源项目。
它提供了一些有用的功能,例如动画 GIF 支持、占位符、变换、缓存和资源重用。
有关更多信息,请查看 Glide 的官方文档。
Coil
Coil 是由 Colin White 创建的,自 2019 年以来越来越受欢迎。
它完全是用 Kotlin 编写的,并且公开的 API 对 Kotlin 友好。一个值得注意的点是,Coil 比其他替代方案更轻,因为它使用了 Android 项目中已经广泛使用的其他库,例如 OkHttp 和 Coroutines。
Coil 还支持 Jetpack Compose,它提供了有用的功能,例如转换、动画 GIF 支持、SVG 支持和视频帧支持。
有关更多信息,请查看 Coil 的官方指南。
Fresco
Fresco 也是流行的图像加载库之一,与 Glide 一样长期以来一直如此。它是由 Meta 开发的。
与其他库不同,Fresco 专注于有效地使用内存,特别是针对 Android 版本 4.x 以下的设备。然而,最近的项目至少要求最低 SDK 版本为 21 到 23,API 非常复杂。除非您正在构建内存敏感的应用程序,否则请选择 Glide 或 Coil。
有关更多信息,请查看 Fresco 的官方指南。
Landscapist
Landscapist是由Jaewoong(skydoves)开发的Jetpack Compose图像加载库,使用Glide、Coil和Fresco获取和显示网络或本地图像。
由于Jetpack Compose将UI渲染机制完全从原始的基于XML的方式改变了,因此开发了Landscapist来以通用的方式支持使用流行的图像加载库进行图像加载。
Landscapist支持跟踪图像状态、组合自定义实现以及动画,如圆形揭示和淡入淡出。最近的一个版本还引入了一个新概念叫做ImagePlugin,可以更轻松、更快速地附加和实现图像加载行为。
欲了解更多信息,请访问Landscapist的GitHub页面。
Local Storage
本地存储是 Android 中另一个常用的解决方案。如果您需要将用户输入或远程资源持久保存在用户的本地设备中,则应将它们保存和还原在本地存储中。
在本节中,我们将探索 Jetpack 的主要本地存储解决方案:Room 和 DataStore。
Room
Room 是由 Google 提供的 Android Jetpack 库,它提供了一个在 SQLite 上的抽象层,简化了查询和访问数据库而无需编写复杂的 SQL 语句。
它基于注释处理器(也支持 Kotlin 符号处理),因此实现(如查询和插入列)将在编译时生成。
使用这个库的最大优势之一是开发人员不需要学习 SQL 查询,因为抽象层非常简洁易懂。它还提供了有用的功能,如协程、RxJava 兼容性、自动迁移策略和类型转换器。
要了解更多关于 Room 的信息,请查看使用 Room 在本地数据库中保存数据培训。
DataStore
DataStore是Google提供的另一个Android Jetpack库,它是一种数据存储解决方案,可以让你在本地存储中存储键值对。这个库是SharedPreferences的另一个解决方案。
DataStore还支持与其他库的高度兼容性,如Coroutines和Flow,以异步方式存储数据,并支持RxJava。它还支持使用协议缓冲区存储类型化对象。
要了解有关DataStore的更多信息,请查看Google的官方文档。
结论
这就是2022年Android开发路线图的第四部分。这一部分涵盖了设计模式、架构、异步、网络、图像加载和本地存储,这些都是现代Android开发的必要组成部分。
《 2022 Android Developer Roadmap》https://github.com/skydoves/android-developer-roadmap
欢迎关注我的公众号“虎哥Lovedroid”,原创技术文章第一时间推送。
声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/93909.html