最近 Android 官方开源了一个新的 App: Now in Android ,这个 App 主要展示了其他 App 可能没有的一些最佳实践、架构设计、以及完整的线上 App (后面会发布到 Google Play 商店中)解决方案,其次是帮助appearance开发者及时了解到自己感兴趣的 Androidshell脚本 开发领域。现在androidstudio安装教程已经在 GitHub 中开源。
通过这篇文章你可shell脚本编程100例以了解到 Now in Android
的应用shell编程架构:分层、关键类以及他们之间的交互架构图怎么制作。
目标&要求
App 的架构目标有以下approve几点:
- 尽可能遵循 官方架构指南 。
- 易于开发人员理解,没有什么太实验性的特性。google
- 支持多个开发人员在同一个代码库上工作。
- 在开发人员的机器上和使用持续集成 (CI) 促进本地和仪器测试。
- 最小化构建时间。
架构概述
App 目前包括 Data layer 和 UI layer ,Domai架构师和程序员的区别n layer 正在开发中。
该架构遵循单向数据流的响应式编程方androidstudio怎么设置中文式。Data Layer
位于底层,主要包括:
-
UI Layer
需androidstudio打包apk对Data Layer
的变化做出反应。 - 事件应向下流动。
- 数据/状态应向上流动。
数据流是采用 Kotlin Flows 来实现的。
示例:在 For you
页面展示新闻信息
Ashell脚本pp 首次运approach行的时候,会尝架构师和程序员的区别试从云端加载新闻列表(选择 staging
或 reshell翻译lease
构建变体时,debug
构建将使用本地数据)。加载后,这些内application容会根据用户选择的兴趣显示给appointment用户。
下图详细展示了事件以及数据是流转的架构图怎么画。
下面是每一步的详细过程。 Code 列中的内容是对应的代码,可以下载项目后在 Android S架构师证书tudio 查看。
步骤 | 描述 | C公积金ode |
---|---|---|
1 | App 启动的时候,WorkManager 的同步任务会把所有的 Reposi架构师和程序员的区别tory 添加到任务队列中。 |
SyncInitializer.create |
2 | 初始状态会设置为 Loading ,这样会在 UI 页面上展示一个旋转的动画。 |
ForYouFeedState.Loading |
3 |
WorkManager 开始执行 OfflineFirstNewsReposshellfishitory 中的同步任务,开始同步远程的数据源。 |
SyncWorker.doWork |
4 |
OfflineFirsappeartNewsRepository 开始调用 RetrofitNiaNandroidstudio简单程序etwork 开始使用 Retrofit 进行真正的网络请求。 |
OfflingoogleeFirstNewsRepository.syncWith |
5 |
RetrofitNiaNetwork 调用云端接口。 |
RetrofitapproachNiaNetwork.getNewsResources |
6 |
Re架构师工资trofitNiaNetwork 接收到远程服务器返回的数据。 |
RappstoreetrofitNiaNetwork.getNewsReso枸杞urces |
7 |
OfflineFirstNewsRepository 通过 NewsResourceDao 将远程数据更新(增删改查)到本地的 Room 数androidstudio新建项目据库中。 |
OfflineFirstNewsRepository.syncWith |
8 | 当 NewsResourceDao 中的数据发生变化的时候,其会被appreciate更新到新闻的数据流(Android+StudioFlow)中。 |
NewsResourceDao.getNewsResourcesStream |
9 |
OshellfishfflineFirstNewsRepos工龄差一年工资差多少itory 扮演数approach据流中的 中间操作符, 将 PopulatedNewsResource (数据层内部数据库的一个实体类) 转换成公开的 NewsResource 实体类供其他层使用。 |
OfflineFirstNewsRepository.getNewsResandroidstudio怎么设置中文ourcesStream |
10 | 当 ForYshell脚本ouViewModel 接收到 Success 成功, ForYouScreen 会使用新的 State 来渲染页面。页面将会展示最新的新闻内容。 |
ForYouFeedState.Success |
Data L架构是什么意思ayer
数据层包含架构图 App 数据以及业务逻辑,会优先提供本地离线数据,它是 App 中所有数据的唯一信源。
每个 Repository
中都有自shell脚本己的实体类(model宫颈癌
/entity
)。如,TopicsRepository
包含 Topic
实体类, NewsRepository
包含 NewsResource
实体类。
Repository
是其他层的公共的 API,androidstudio线性布局提供架构图怎么画了访问 App 数据的唯一途径shell命令。Repository
通常提供一种或多种androidstudio模拟器运行不出来数据读取和写入的方法。
读取数据
数据通过数据流提供。这意味着 Repository
的工资超过5000怎么扣税调用者都必须准备好对数据的变化做出响应。数据不会作为快照(例如 getModel
)提供,因为无法确保它在使用时仍然有效。
Repository
以本地存储数据作为单一信源,因此从实androidstudio打包apk例读取时不会出现错误。但公积金是,当尝试将本地存储中的数据与云端数据进行合并时,可能会发生错误。有关错误的更多信息appearance,请查看下面的数据同步部分。架构图怎么制作
示例:读shellfish取架构师和程序员的区别作者信息
可以用过订阅 AShelluthoandroidstudio打包apkrsRepository::getAutappreciatehorsStream
发出的流来获得 List<Authors>
信息。每当作者列表更改时(例如,添加新作者时),更新后的 List<Author>
的内容都会发送到数据流中。如下:
class OfflineFirstTopicsRepository @Inject constructor(
private val topicDao: TopicDao,
private val network: NiANetwork,
private val niaPreferences: NiaPreferences,
) : TopicsRepository {
// 监听 Room 数据的变化,当数据发生变化的时候,调用者就会收到对应的数据
override fun getTopicsStream(): Flow<List<Topic>> = topicDao.getTopicEntitiesStream().map {
it.map(TopicEntity::asExternalModel)
}
// ...
}
写入数据
为了写入数据,Repository
库提供了 suspend
函数。由调用者来确保它们在合适的 scope
中被执行。
示例: 关注 Topic
调用 TopicsRepository.setFollowedTopicId
将用户想要关注的 topic i架构d 传入即可。
在 OfflineFirstTopicsRepositoryandroidstudio怎么设置中文
中定义:
interface TopicsRepository : Syncable {
suspend fun setFollowedTopicIds(followedTopicIds: Set<String>)
}
在 ForYouViewModel
中定义:
class ForYouViewModel @Inject constructor(
private val topicsRepository: TopicsRepository,
// ...
) : ViewModel() {
// ...
fun saveFollowedInterests() {
// ...
viewModelScope.launch {
topicsRepository.setFollowedTopicIds(inProgressTopicSelection)
// ...
}
}
}
数据源(Data Sources)
Repository
可能依赖于一个或多个 DataSource
。例如,OfflineFirstTo架构师picsReposiandroidstudio安装教程tory
依赖以下数据架构是什么意思源:
名称 | 使用 | 目的 |
---|---|---|
TopicsDao | Room/SQLite | 持久化和 Topics 相关的关系型数据。 |
NiaPreferences | Proto DataStore | 持久化和用户相关的非结构化偏好数据,主要是用户感兴趣的 Topics 内容appetite。这里使用架构师的是 .proto 文件。 |
NiANetwork | Retrofit | 云端以 JSON 形式提供对应的 Topics 数据。 |
数据同步
Repository
的职责之一就是整架构图怎么画合本地数据与云端数据。一旦从云端返回数据就会立即将其写入本地数据中。更新后的数据shell命令将会从本地数据(Room
)中发送到相关的数据流中,调用者便可以监shell是什么意思中文听到对应的变化。
这种方法可确保应用程序的读取和写入关注点是分开的,不会相互干扰androidstudio新建项目。
在数据同步过程中出现错架构图怎么画误的情况下,应采用对应的回退策略。App 中是经由 SyncWorker
代理appstore给 WorkManager
的。 SyncWorker
是 Synchronizer
的实现类。
可以通过公积金 OfflineFirstNewsRepository.syncWith
来查看数据同步的示例,如下:
class OfflineFirstNewsRepository @Inject constructor(
private val newsResourceDao: NewsResourceDao,
private val episodeDao: EpisodeDao,
private val authorDao: AuthorDao,
private val topicDao: TopicDao,
private val network: NiANetwork,
) : NewsRepository {
override suspend fun syncWith(synchronizer: Synchronizer) =
synchronizer.changeListSync(
versionReader = ChangeListVersions::newsResourceVersion,
changeListFetcher = { currentVersion ->
network.getNewsResourceChangeList(after = currentVersion)
},
versionUpdater = { latestVersion ->
copy(newsResourceVersion = latestVersion)
},
modelDeleter = newsResourceDao::deleteNewsResources,
modelUpdater = { changedIds ->
val networkNewsResources = network.getNewsResources(ids = changedIds)
topicDao.insertOrIgnoreTopics(
topicEntities = networkNewsResources
.map(NetworkNewsResource::topicEntityShells)
.flatten()
.distinctBy(TopicEntity::id)
)
// ...
}
)
}
UI Layer
UI Layer 包含:
- Jeandroidstudio安装教程tpack Compose 中的 UI 元APP素。
- Andrandroidstudio安装教程oid ViewMode 。
ViewModeapplicationl
从 Repository
接收数apple据流并将其转换为 UI State。UI 元素根据 UI State 进架构师行渲染,并为用户提供了与 App 交互的方式。这些交互作为事件(UI Eveshell命令nt)传递到对应的 Viewandroidstudio彻底卸载干净Model
中。
构建 UI State
UI Stat架构图e
一般shell什么意思是通过接口和 data class
来组装的密封类。Stashell什么意思te 对象只能通过数据流的转换发出。这种方法可确保:
-
UI State
始appetite终代表底层应用程序数据 – Apshell翻译p 中的单一信源。 - UI 元素处理所有可能的
UI State
。
示例:For You
页面的新闻列表
For You
页面的新闻列表数据源是 ForYouFeedState
,他是一个 sealed interface
类,包含 Loading
和 Success
两种状态:
-
Lo架构工程师ading
表示数据正在加载。 -
Success
表示数据加载成功。Success 状态包含新闻资源列表。
sealed interface ForYouFeedState {
object Loading : ForYouFeedState
data class Success(val feed: List<SaveableNewsResource>) : ForYouFeedState
}
ForY架构图怎么制作ouScreen
中会处理 feedState
的这两种状态,如下:
private fun LazyListScope.Feed(
feedState: ForYouFeedState,
//...
) {
when (feedState) {
ForYouFeedState.Loading -> {
// show loading
}
is ForYouFeedState.Success -> {
// show feed
}
}
}
将数据流转换为 UI Statandroidstudio彻底卸载干净e
ViewModel
从一个或者多个 Repository
中接收数据流当做冷流 。将他们一起 组合 成单一的 UI State。架构图怎么制作然后使用 st公司让员工下班发手机电量截图ateInappear 将冷流转换成热流。转换的状态流使 UI 元素可以读取到数据流中最后的状态。工商银行
示例: 展示已关注的话题及作者
InterestsViewModel
暴露 SappreciatetateFlow<FollowingUiState>
类型的 uiState
。通过组合 4 个数据流来创建热流:
- 作shell翻译者列表
- 已关注的作者 ID 列表
- Topics 列表
- 已关注 Topicsshell脚本编程100例 列表的 IDs
将 Author
转换为公积金 FollowableAuthor
,FollowableAuthor
是对 Author 的包装类, 添加了当application前用户龚俊是否已经关注了作者。对 Topic
也做了相同appstore转换。 如下:
val uiState: StateFlow<InterestsUiState> = combine(
authorsRepository.getAuthorsStream(),
authorsRepository.getFollowedAuthorIdsStream(),
topicsRepository.getTopicsStream(),
topicsRepository.getFollowedTopicIdsStream(),
) { availableAuthors, followedAuthorIdsState, availableTopics, followedTopicIdsState ->
InterestsUiState.Interests(
// 将 Author 转换为 FollowableAuthor,FollowableAuthor 是对 Author 的包装类,
// 添加了当前用户是否已经关注了作者
authors = availableAuthors
.map { author ->
FollowableAuthor(
author = author,
isFollowed = author.id in followedAuthorIdsState
)
}
.sortedBy { it.author.name },
// 将 Topic 转换为 FollowableTopic,同 Author
topics = availableTopics
.map { topic ->
FollowableTopic(
topic = topic,
isFollowed = topic.id in followedTopicIdsState
)
}
.sortedBy { it.topic.name }
)
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = InterestsUiState.Loading
)
两个新的列表创建了新的 FollowingUiStapproachate.In架构图terests
UiState
暴露给 UI 层。
处理用户交互
用户对 UI 元素的操作通过常规的函数调用传递给 ViewModel
,这些方法作为 lambda
表达式传递给 UI 元素。
示例:关注话题
InterestsScreen
通过 followTopic
lambda 表达式传递事件,然后会调用到 In架构图terestsV架构是什么意思iewMod公司让员工下班发手机电量截图el.followTopic
函数。当用户Shell点击关注话题的时候,函数将会被调用。然后 ViewModel
就会通过通知 TopicsRepoappetitesitory
处理对应架构师证书的用户操作。
如下在 InterestsRoute
中关联 InterestsScreen
与 InterestsViewModel
:
@Composable
fun InterestsRoute(
modifier: Modifier = Modifier,
navigateToAuthor: (String) -> Unit,
navigateToTopic: (String) -> Unit,
viewModel: InterestsViewModel = hiltViewModel()
) {
val uiState by viewModel.uiState.collectAsState()
val tabState by viewModel.tabState.collectAsState()
InterestsScreen(
uiState = uiState,
tabState = tabState,
followTopic = viewModel::followTopic,
// ...
)
}
@Composable
fun InterestsScreen(
uiState: InterestsUiState,
tabState: InterestsTabState,
followTopic: (String, Boolean) -> Unit,
// ...
) {
//...
}
扩展阅读
本文主要是根据 Now in Android 中的 Architecture Learning Journey 整理而得,感兴趣的可以进shell翻译一步阅读原文。除此之外,还可以进公司让员工下班发手机电量截图一步学习 Android 官方相关的资料:
- Guide to app architecture
- Jetpack Compos架构师工资e
关于架构指appreciate南部分,我之前也整理了部分对应的解读部分,大家可以移步appreciate查看
- Arch –Shell 概述
- Arch – UI Layer
- Arch – Domain Laandroidstudio快捷键yer
- Arch – Data L工商银行ayer
- Arch – 总结
更多内容会第一时间发布在微信公众号中,欢迎大家关注: