app开发者面临的常见问题
一个典型的Android应用程序由多个应用程序组件构成,包括活动(activities),片段(fragments),服务(services),内容提供商(content providers)和广播接收器(broadcast receivers)。
app组件可以单独和无序地启动,并且可以在任何时候由用户或系统销毁。由于应用程序组件是短暂的,并且它们的生命周期(创建和销毁时)不受您的控制,因此您不应该在应用程序组件中存储任何应用程序数据或状态,并且应用程序组件不应相互依赖。
共同的架构原则
原则一:任何不处理UI或操作系统交互的代码都不应该在Activity和Fragment类中。尽可能保持精简可以避免许多生命周期相关的问题。不要忘记,您不拥有这些类,它们只是体现操作系统和您的应用程序之间契约的胶合类。基于用户交互或其他因素(如低内存),Android操作系统可能随时销毁它们。最好尽量减少对他们的依赖,以提供可靠的用户体验。
原则二:应该从一个模型model驱动UI,最好是一个持久模型。模型是负责处理应用程序数据的组件。它们独立于应用程序中的视图和应用程序组件,因此它们与这些组件的生命周期问题相隔离。将您的应用程序放在模型类上,具有明确的数据管理责任将使它们可测试并且您的应用程序保持一致。
构建用户界面
甲 视图模型 提供了一个特定的UI组件中的数据,如一个片段或活性,和处理与数据处理的部分业务,如主叫其他组件加载数据或转发的用户修改的通信。ViewModel不知道视图,并且不受配置更改的影响,例如由于旋转而重新创建活动。
当设置ViewModel的用户字段时,我们需要一种方法来通知用户界面。这是LiveData类的用途。
LiveData是一个可观察的数据持有者。它允许应用程序中的组件观察
LiveData
对象以进行更改,而不会在它们之间创建明确和严格的依赖关系路径。LiveData还尊重应用程序组件(活动,片段和服务)的生命周期状态,并做正确的事情来防止对象泄漏,以便您的应用程序不会消耗更多内存。
管理组件之间的依赖关系:
UserRepository
上面的类需要一个实例Webservice
来完成它的工作。它可以简单地创建它,但要做到这一点,它也需要知道Webservice
类的依赖关系来构造它。这会使代码复杂化并重复(例如,每个需要Webservice
实例的类 都需要知道如何用它的依赖关系来构造它)。
有两种模式可以用来解决这个问题:
- 依赖注入:依赖注入允许类在不构建它们的情况下定义它们的依赖关系。在运行时,另一个类负责提供这些依赖关系。我们推荐Google的Dagger 2库在Android应用中实现依赖注入。Dagger 2通过遍历依赖关系树自动构造对象,并为依赖关系提供编译时保证。
- 服务定位器:服务定位器提供了一个注册表,类可以获得它们的依赖关系而不是构建它们。实施起来要比依赖注入(DI)容易,所以如果您不熟悉DI,请改用服务定位器。
指导原则
编程是一个创造性领域,构建Android应用程序并不例外。有很多方法可以解决问题,无论是在多个活动或片段之间传递数据,检索远程数据并将其保存在本地以用于脱机模式,还是其他任何常见应用程序都遇到不寻常的应用程序。
尽管以下建议不是强制性的,但我们的经验是,遵循这些建议将使您的代码基础更加健壮,可测试并可长期维护。
- 您在清单中定义的入口点 - 活动,服务,广播接收器等 - 不是数据的来源。相反,他们只应该协调与该入口点相关的数据子集。由于每个应用程序组件的寿命相当短,这取决于用户与设备的交互以及运行时的整体当前运行状况,因此您不希望任何这些入口点成为数据源。
- 无情地在应用程序的各个模块之间创建明确界定的责任。例如,不要将代码从网络中加载数据到代码库中的多个类或包中。同样,不要将不相关的职责 - 例如数据缓存和数据绑定 - 放到同一个类中。
- 尽可能少地暴露每个模块。不要试图创建“只有那一个”快捷方式,从一个模块公开内部实现细节。您可能在短期内获得一些时间,但随着代码库的发展,您将多次支付技术债务。
- 在定义模块之间的交互时,请考虑如何让每个模块单独进行测试。例如,有一个定义良好的API从网络中获取数据将使测试将数据保存在本地数据库中的模块变得更加容易。相反,如果将来自这两个模块的逻辑混合在一起,或者在整个代码库中使用网络代码,那么测试起来会更加困难 - 即使不是不可能 - 也是如此。
- 你的应用程序的核心是什么让它从其他中脱颖而出。不要花太多时间重复发明轮子或一次又一次地写出相同的样板代码。相反,将精力集中在让您的应用独特的东西上,让Android Architecture组件和其他推荐的库处理重复的样板。
- 尽可能多地保持相关和新鲜的数据,以便在设备处于离线模式时您的应用程序可用。虽然您可以享受持续高速的连接,但您的用户可能不会。
- 您的存储库应该指定一个数据源作为单一的事实来源。只要你的应用程序需要访问这部分数据,它应该始终来自单一的事实来源。