推荐的Android app应用程序架构实践

本文介绍了Android应用的架构设计原则,强调了数据层和UI层的分离。数据层应包含业务逻辑,通过Repository管理多个数据源,并通过不可变的数据模型驱动UI。UI层则负责显示数据和用户交互,采用单向数据流管理状态,避免直接修改UIState。建议遵循关注点分离、减少对Android类的依赖以及确保应用数据的独立性和一致性。
摘要由CSDN通过智能技术生成

参考

1.Guide to app architecture
https://developer.android.com/jetpack/guide

总结概述(Overview)

Given the condition of this environment, it’s possible for your app to be launched individually and out-of-order,
and the operating system or user can destroy them at any time. Because these events aren’t under your control,you
shouldn’t store or keep in memory any application data or state in your app components, and your app components shouldn’t
depend on each other.

Common architectural principles:

1.An app architecture defines the boundaries between parts of the app and the responsibilities each part should have.

2.separation of concerns(关注点分离)
It’s a common mistake to write all your code in an Activity or a Fragment.These UI-based classes
should only contain logic that handles UI and operating system interactions.
Keep in mind that you don’t own implementations of Activity and Fragment; rather, these are just glue classes that represent the contract between the Android OS and your app. the OS can destroy them at any time, it’s best to minimize your dependency on them.

3 . Drive UI from data models(从数据模型驱动UI)
Data models represent the data of an app. they’re independent from the UI elements and other components in your app. This means that they are not tied to the UI and app component lifecycle

Recommended app architecture:

1.Each application should have at least two layers:
1.1 The UI layer that displays application data on the screen.
1.2 The data layer that contains the business logic of your app and exposes application data.
1.3 you can add a additional layer called domain layer to simplify and reuse the interactions between the uI and data layers.

General best best practices

1.Don’t store data in app components
2.Reduce dependencies on Android classes.
3.create well-defined boundaries of responsibility between various modules in your app.
4.expose as little as possible from each module.
5.focus on the unique core of your app so it stands out from other apps.
6.consider how to make each part of your app testable in isolation.
7.persist as much relevant and fresh data as possible.

参考:Guide to app architecture
https://developer.android.com/jetpack/guide

数据层:

数据层负责向应用提供数据,需要保证数据的可靠和唯一,和正确一致.

可以分成两层:

repository层:负责暴露数据给应用,需要管理一个或多个数据源 data source,并进行业务逻辑处理后.生成内部成员变量等供外部使用.

data source层:每个 data source 类应该只负责一个数据源,比如一个本地文件或一个网络数据,或一个本地数据库.
应用中除了repository层的类其他层都不可用直接访问和依赖与data source层类.

1.数据层暴露的数据应该是不可变的.不能被其他类篡改,否则会导致不一致问题.

2.数据层通常暴露增删改查方法给外部.

e.g.新闻app:

// repository层类:
class NewsRepository( 
	private val newsRemoteDataSource: NewsRemoteDataSource,
	// This could be CoroutineScope(SupervisorJob() + Dispatchers.Default)可以近似看做是一个线程池
	private val externalScope: CoroutineScope
) {

	// Mutex to make writes to cached values thread-safe
	private val latestNewsMutex = Mutex()

	// Cache of the latest news got from the network.
	private var latestNews: List<ArticleHeadline> = emptyList()

	suspend fun getLatestNews(refresh: Boolean = false): List<ArticleHeadline> {
		return if (refresh) {
			externalScope.async {
				newsRemoteDataSource.fetchLatestNews().also {networkResult ->
				      //Thread-safe write to latestNews.
				       latestNewsMutex.withLock{
					   latestNews = networkResult				       
				       }
				}			
			}.await()
		} else {
			return latestNesMutex.withLock{this.latestNews}
		}	
	}
}
// data source层类:
class NewsRemoteDataSource(
	private val newsApi: NewsApi,
	private val ioDispatcher: CoroutineDispatcher
){
	// this executes on an IO-optimized thread pool, the function is main-safe.
	suspend fun fetchLatestNews(): List<ArticleHeadLine> =
		withContext(ioDispatcher) {
			newsApi.fetchLatestNews()
		}
	}

}

// make news-related network synchronous requests.
interface NewsApi {
	fun fetchLatestNews(): List<ArticalHeadLine>
}

UI层:

负责在屏幕上显示应用的数据,并与用户交互.

可以分为两层:

UI elements层: consume and display UI state.

State holders层: the production of UI state and contain the necessary logic for that task.

UI层必须执行如下步骤:

1.消费应用数据,并转换为UI可以容易渲染的数据.
2.消费可渲染数据,并转换它进入UI elements用于呈现给用户.
3.消费用户输入事件(来自于UI elements),并反馈到UI data.

下面展示如何实现UI层,以实现上述步骤:

1.定义UI State

UI Elements + UI State = UI

UI is a result of binding UI elements on the screen with the UI state.

(1) The UI state definition is immutable(不可变)
这样可以让UI单纯关注与从UI State中读取.而不应该从UI直接修改UI State(除非UI是UI State的唯一数据来源).
违反这个原则会导致数据多个来源,和数据不一致.比如:如果UI State中的订阅状态可以被Activity更新,这个状态更新
就会和来自数据层的订阅状态竞争.

Key Point: Only source or owners of data should be responsible for updating the data they expose.
只应该由数据拥有者负责更新他们提供的数据.

2.使用单向数据流来管理状态(Manage state with Unidirectinal Data Flow)

|UI elements| -(events)–> |viewmodel| |data layer|
<-(UI state)- <-(App data)-

(1) the viewmodel holds and exposes the state to be consumed by the UI. The UI state is app data transformed by the viewmodel.
(2) the UI notifies the viewmodel of user events.
(3) the viewmodel handles the user actions and updates the state.
(4) the updated state is fed back to the UI to render.
(5) the above is repeated for any event that causes a mutation of state.

在这里插入图片描述

2.1 Types of logic

Business logic: is what to do with state change.

UI behavior logic or UI logic: is how to display state change on the screen.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值