我在“Now In Android”中学到的 9 件事

news2024/11/23 15:22:43

我在“Now In Android”中学到的 9 件事

Now In Android

Now in Android是一款功能齐全的 Android 应用程序,完全使用 Kotlin 和 Jetpack Compose 构建。它遵循 Android 设计和开发最佳实践,旨在为开发人员提供有用的参考。

https://github.com/android/nowinandroid

UI 状态类

sealed interface InterestsUiState {
    object Loading : InterestsUiState

    data class Interests(
        val authors: List<FollowableAuthor>,
        val topics: List<FollowableTopic>
    ) : InterestsUiState

    object Empty : InterestsUiState
}

此类旨在保存屏幕上显示的流数据,这些数据将随时间或事件发生变化,例如:调用 API 显示动作电影的流将需要视图来显示加载屏幕(以防请求花费太长时间)在显示查询结果之前,如果发现异常则显示错误屏幕。

在发现这一点之前,我是这样管理视图模型中屏幕上显示的流数据的:

var authors: LiveData<List<FollowableAuthor>> = MutableLiveData(emptyList())
var topics: LiveData<List<FollowableTopic>> = MutableLiveData(emptyList())

val isLoading = MutableLiveData(true)

val isEmpty: LiveData<Boolean> = authors.switchMap { authors ->
    topics.map { topics ->
        topics.isEmpty() && authors.isEmpty()
    }
}

init {
    viewModelScope.launch {
        authors = authorsRepository.getAuthorsStream()
        topics = topicsRepository.getTopicsStream()
    }.invokeOnCompletion {
        isLoading.value = false
    }
}

现在代码看起来像这样:

val uiState = combine(
    authorsRepository.getAuthorsStream(),
    topicsRepository.getTopicsStream(),
) { availableAuthors, availableTopics ->
    InterestsUiState.Interests(
        authors = availableAuthors,
        topics = availableTopics
    )
}.stateIn(
    scope = viewModelScope,
    started = SharingStarted.WhileSubscribed(5_000),
    initialValue = InterestsUiState.Loading
)

(在这个例子中,我从 LiveData 切换到 StateFlow,但实际上使用“asLiveData()”和“asFlow()”方法仍然很容易互换)
State holder & UI State
https://developer.android.com/topic/architecture/ui-layer/state-production#stream-apis

使用构造函数引用转换流

val myStream = combine(
  followedAuthorIdsStream,
  authorStream,
  ::Pair
)

而不是“手动”映射它…

val myStream = 
combine(
  followedAuthorIdsStream,
  authorStream,
) { followedAuthorIds, author -> 
    Pair(followedAuthorIds, author)
}

“::Class”被称为构造函数引用。构造函数可以像方法和属性一样被引用。您可以在程序需要函数类型对象的任何地方使用它们,该对象采用与构造函数相同的参数并返回适当类型的对象。

轻松将其映射到密封接口结果中

return combine(
  followedAuthorIdsStream,
  authorStream,
  ::Pair
).asResult() // <- The change is here !

因为我们之前将我们的流配对成单个流,所以我们可以将它映射到一个会改变的结果类中,就像UIState类一样,但是以一种更通用的方式,因为 Result.Success将公开一个字段:数据

sealed interface Result<out T> {
    data class Success<T>(val data: T) : Result<T>
    data class Error(val exception: Throwable? = null) : Result<Nothing>
    object Loading : Result<Nothing>
}

Flow上的 Kotlin 扩展可自动映射到Result

fun <T> Flow<T>.asResult(): Flow<Result<T>> {
    return this
        .map<T, Result<T>> {
            Result.Success(it)
        }
        .onStart { emit(Result.Loading) }
        .catch { emit(Result.Error(it)) }
}

将其映射到 UI 状态类中

return combine(
  followedAuthorIdsStream,
  authorStream,
  ::Pair
).asResult()
.map { followedAuthorToAuthorResult ->
    when (followedAuthorToAuthorResult) {
        is Result.Success -> {
            val (followedAuthors, author) = followedAuthorToAuthorResult.data
            AuthorUiState.Success()
        }
        is Result.Loading -> AuthorUiState.Loading
       
        is Result.Error -> AuthorUiState.Error
    }
}

使用生命周期安全方法搜集状态

val uiState by viewModel.uiState.collectAsStateWithLifecycle()

我正在使用 collectAsState() 并且没有注意到生命周期版本已经结束。

collectAsState()方法的提醒:

@Composable
public fun <T> StateFlow<T>.collectAsState(
 context: CoroutineContext
): State<T>

从此 StateFlow 收集值并通过 State 表示其最新值。StateFlow.value 用作初始值。每次有新值发布到 StateFlow 时,返回的 State 都会更新,从而导致每个 State.value 用法的重组。

Composable 中的方法引用

@Composable
fun MyScreen(viewModel: ForYouViewModel) {

  ForYouScreen(
      onTopicCheckedChanged = viewModel::updateTopicSelection,
      onAuthorCheckedChanged = viewModel::updateAuthorSelection,
      saveFollowedTopics = viewModel::saveFollowedInterests,
      onNewsResourcesCheckedChanged = viewModel::updateNewsResourceSaved,
  )
}

这使代码更具可读性,特别是在这里,您的眼睛需要关注 UI。
调用参考:

@Composable
fun MyScreen(viewModel: ForYouViewModel) {

  ForYouScreen(
      onTopicCheckedChanged = { topicId, isChecked ->
        viewModel.updateTopicSelection(topicId = topicId, isChecked = isChecked)
      },
      onAuthorCheckedChanged = { authorId, isChecked ->
        viewModel.updateAuthorSelection(authorId = authorId, isChecked = isChecked)
      },
      saveFollowedTopics = { viewModel.saveFollowedInterests() },
      onNewsResourcesCheckedChanged = { newsResourceId, isChecked ->
        viewModel.updateNewsResourceSaved(
           newsResourceId = newsResourceId,
           isChecked = isChecked
        )
     },
  )
}

多预览的注解

表示各种设备尺寸的多预览的注解。将此注解添加到Composable以呈现各种设备。

@Preview(name = "phone", device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480")
@Preview(name = "landscape", device = "spec:shape=Normal,width=640,height=360,unit=dp,dpi=480")
@Preview(name = "foldable", device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480")
@Preview(name = "tablet", device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480")
annotation class DevicePreviews

在同一个窗口中使用单个注解显示横向和纵向模式真的很酷
Multipreview注解表示不同设备尺寸的多个预览。可以将这个注解添加到Compose中的某个组件上,以在不同设备上渲染多个预览界面。

中创建的自定义控件

Android允许您通过继承IssueRegistry来创建自定义lint规则,示例如下(我不会解释如何做,因为我在我的项目中还没有成功地让它正常工作):

class DesignSystemIssueRegistry : IssueRegistry()

在最新的Android版本中,他们创建了一个类来检查是否使用了他们自定义的组件而不是通用的组件。以下是他们编写的代码片段:

class DesignSystemDetector : Detector(), Detector.UastScanner {

  ...

  val METHOD_NAMES = mapOf(
            "MaterialTheme" to "NiaTheme",
            "Button" to "NiaFilledButton",
            "OutlinedButton" to "NiaOutlinedButton",
            ...
            )
}

我发现这对不知道项目中已经存在特定组件的新开发人员很有用。

Composable 扩展

它只适用于 LazyListScopeColumnScope ……不适用于 @Composable

fun LazyListScope.MyItem() {
  item {
    // Your Composable
  }
}

@Composable
fun MyList() {
  LazyColumn {
    MyItem()
  }
}

我发现这很有用,例如:在多个屏幕上共享可组合的粘性标头。

先前:

@Composable
fun MyStickyHeader() {
  // Composable
}

@Composable
fun MyList() {
  LazyColumn {
    stickyHeader {
      MyStickyHeader()
    }
  }
}

之后:

fun LazyListScope.MyStickyHeader() {
  stickyHeader {
    // Composable
  }
}

@Composable
fun MyList() {
  LazyColumn {
    MyStickyHeader()
  }
}

参考链接

https://medium.com/@romeo.prosecco/top-things-i-learned-on-now-in-android-dba991da1c0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/430181.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

淘宝悄悄内测“店号一体”的新模式

4月17日消息&#xff0c;淘宝近日已开始小规模测试“店号一体”新模式。新模式下&#xff0c;淘宝店铺将与逛逛、直播等账号完全打通&#xff1b;此前针对达人及内容型商家的新店铺模式“视频内容店”也同步升级。 内测商家透露&#xff0c;目前在淘宝发布的图文、短视频、直播…

腾讯学长分享的这份Java面试八股文手册,让我GitHub下载量破百万!!!

一些不满现状&#xff0c;被外界的“高薪”“好福利”吸引的人&#xff0c;一般就在这时候毅然决然地跳槽了。 跳槽是为了寻求更好的发展&#xff0c;但在跳槽前我们也不能确定下家就是更好的归宿&#xff0c;这就更加需要我们审慎地去对待&#xff0c;不能盲目跳槽。 其次&a…

知识图谱专栏简介:数据增强,智能标注,文本信息抽取(实体关系事件抽取)、知识融合算法方案、知识推理、模型优化、模型压缩技术等

知识图谱专栏简介&#xff1a;数据增强&#xff0c;智能标注&#xff0c;文本信息抽取&#xff08;实体关系事件抽取&#xff09;、知识融合算法方案、知识推理、模型优化、模型压缩技术等 专栏链接&#xff1a;NLP知识图谱相关技术业务落地方案和码源 NLP知识图谱相关技术业…

程序员跳槽薪水涨了一倍,谈谈java工程师找新工作的八大技巧

大家好&#xff0c;这几天发生了一些事情&#xff0c;我找到了一份新工作&#xff0c;明天是第一天上班。我想先谈一下我的新工作待遇&#xff0c;因为我觉得相对来说还算比较满意。接下来我想谈一下我的个人经历&#xff0c;从毕业到现在的工作经历。第三个话题是我最近半个月…

k-d Tree算法

1.概述 本文介绍一种用于高维空间中的快速最近邻和近似最近邻查找技术——Kd- Tree(Kd树)。Kd-Tree&#xff0c;即K-dimensional tree&#xff0c;是一种高维索引树形数据结构&#xff0c;常用于在大规模的高维数据空间进行最近邻查找(Nearest Neighbor)和近似最近邻查找(Appro…

Java工程行业管理系统源码-专业的工程管理软件-提供一站式服务

Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目显示1…

反向代理自建教程:你懂的

一、为什么需要自建反代 OpenAI提供了两种访问方式&#xff0c;一种是直接在ChatGPT网页端使用的Access Token方式&#xff0c;这种方式可以免费使用GPT-3.5模型&#xff0c;只需要登录即可使用。但缺点是不稳定&#xff0c;且无法扩展。另一种是使用API&#xff0c;注册用户可…

Nacos 客户端服务注册源码分析-篇三

Nacos 客户端服务注册源码分析-篇三 版本说明&#xff1a; 源码版本 nacos-1.4.2 Nacos 的核心功能点 服务注册&#xff1a; Nacos Client 会通过发送 REST 请求的方式向 Nacos Server 注册自己的服务&#xff0c;提供自身的元数据&#xff0c;比如 ip 地址以及端口等信息。Na…

Sentinal持久化到Nacos

Springboot应用整合Sentinel实现限流、熔断、降级笔记https://blog.csdn.net/chenjian723122704/article/details/130101875 Sentinel版本 1.8.6 Nacos版本 2.2.0 下载Sentinel源码 Sentinel1.8.6&#xff1a;https://github.com/alibaba/Sentinel/releases/tag/1.8.6 拷贝源…

AtCoder Beginner Contest 295——F - substr = S

蒟蒻来讲题&#xff0c;还望大家喜。若哪有问题&#xff0c;大家尽可提&#xff01; Hello, 大家好哇&#xff01;本初中生蒟蒻讲解一下AtCoder Beginner Contest 295这场比赛的F题&#xff01; F - substr S 原题 Problem Statement You are given a string SSS consisti…

双塔模型:微软DSSM模型浅析

1.背景 DSSM是Deep Structured Semantic Model (深层结构语义模型) 的缩写&#xff0c;即我们通常说的基于深度网络的语义模型&#xff0c;其核心思想是将query和doc映射到到共同维度的语义空间中&#xff0c;通过最大化query和doc语义向量之间的余弦相似度&#xff0c;从而训…

2023好玩的解压游戏,压力大点开玩可以放松自己

你是不是经常感觉到压力大&#xff1f; 现代社会&#xff0c;竞争逐步激烈&#xff0c;不管是来自学习上&#xff0c;工作上&#xff0c;还是生活上的&#xff0c;压力都非常大&#xff01; 这时候&#xff0c;我们要学会自我减压&#xff0c;有效的放松是为了更好地前行。 …

JavaWeb开发 —— MyBatis基本操作

目录 一、环境准备 二、删除操作实现 1. 根据主键删除 2. 删除&#xff08;预编译SQL&#xff09; 2.1 SQL注入 2.2 参数占位符 三、新增操作实现 1. 新增代码实现 2. 新增&#xff08;主键返回&#xff09; 四、更新操作实现 五、查询操作实现 1. 根据ID查询 1.1…

【Python】pip 和 conda install、list的区别,是否一致

【Python】pip 和 conda install、list的区别&#xff0c;是否一致 文章目录【Python】pip 和 conda install、list的区别&#xff0c;是否一致1. 介绍2. 看效果2.1 首先&#xff0c;conda 创建环境2.2 然后&#xff0c;激活环境2.3 查看环境下已经安装包列表2.4 安装新的包&am…

【2023最新】超详细图文保姆级教程:App开发新手入门(2)

上章节我们已经成功的创建了一个 App 项目&#xff0c;接下来我们讲述一下&#xff0c;如何导入项目、编辑代码和提交项目代码。 Let’s Go! 4. 项目导入 当用户创建一个新的应用时&#xff0c;YonStudio 开发工具会自动导入模板项目的默认代码&#xff0c;不需要手动进行代…

C语言的Hello World的汇编剖析(64位 Intel架构)

C语言的Hello World的汇编剖析&#xff08;64位 Intel架构&#xff09; 文章目录C语言的Hello World的汇编剖析&#xff08;64位 Intel架构&#xff09;一. 前提准备二. C转换为汇编操作准备2.1 创建目录&复制代码2.2 C文件转换为汇编文件三. 剖析汇编文件四. 指令相关五. …

TenserRT(三)PYTORCH 转 ONNX 详解

第三章&#xff1a;PyTorch 转 ONNX 详解 — mmdeploy 0.12.0 文档 torch.onnx — PyTorch 2.0 documentation torch.onnx.export 细解 计算图导出方法 TorchScript是一种序列化和优化PyTorch模型的格式&#xff0c;将torch.nn.Module模型转换为TorchScript的torch.jit.Scr…

ERTEC200P-2 PROFINET设备完全开发手册(6-1)

6 报警和诊断 Profinet提供了强大的诊断功能&#xff0c;这是其他通讯协议所无法比拟的。PN设备检测到问题后可以向控制器发送报警信息&#xff0c;报警分为三大类&#xff1a; 诊断报警 &#xff08;PN设备本身故障触发的报警&#xff0c;例如&#xff1a;温度测量通道变送电…

Activiti学习02

这里写目录标题一、流对象简介1.1 事件1.2 活动1.3 条件二、Activiti系统服务结构图核心类:服务类:RepositoryServiceRuntimeServiceTaskServiceHistoryServiceFormServiceIdentityServiceManagementService三、Activiti数据库支持一、流对象简介 一个业务流程图有三个流对象的…

ATFX国际:中国一季度GDP同比增长4.5%,社消总额约11.5万亿元

ATFX国际&#xff1a;中国统计局发布一季度国民经济运行报告&#xff0c;其中值得关注两大数据分别为GDP同比增速、社会消费品零售总额增速。统计显示&#xff0c;一季度GDP总额28.5万亿元&#xff0c;同比增长4.5%&#xff0c;其中第一产业和第二产业的增速低于平均值&#xf…