当前位置: 首页 > news >正文

Jetpack Compose初体验

入门学习

由于工作需要,我们当前要在老代码的基础上使用 Compose 进行新页面的开发,这项工作主要落在我的身上。因此,我需要先了解 Compose。

这里我入门看的是写给初学者的Jetpack Compose教程,Lazy Layout,有兴趣可以看看。

了解 Compose

Compose 是 Google 推出的用于构建原生界面的现代工具包,专门用于 Android 平台的声明式 UI 开发。基于 Kotlin 语言,Compose 利用 Kotlin 的特性来简化 UI 开发过程,核心思想是使用函数来描述 UI 的外观和行为。

Compose 与传统 Android 开发的区别

1. 编程范式
  • 传统 Android 开发:采用命令式编程范式,开发者需要手动管理 UI 组件的创建、更新和销毁。
  • Compose 开发:采用声明式编程范式,开发者只需描述 UI 的最终状态,Compose 会自动更新 UI。
2. 布局系统
  • 传统 Android 开发:使用 XML 布局文件和 Java/Kotlin 代码分离的方式。
  • Compose 开发:使用 Kotlin 代码直接构建布局,布局代码和逻辑代码可以放在一起。
3. 状态管理
  • 传统 Android 开发:手动处理状态的保存和恢复。
  • Compose 开发:内置状态管理机制,使用 mutableStateOf,状态变化会自动更新 UI。
4. 开发效率
  • 传统 Android 开发:代码量较大,开发效率相对较低。
  • Compose 开发:代码简洁,声明式编程和内置状态管理机制提高了开发效率。

初试 Compose

从 AI 的搜索结果来看,Compose 开发具有以下特点:声明式编程、基于 Kotlin、高效的状态管理、简洁的布局系统、实时预览、与现有代码兼容。

环境搭建

想要进行 Compose 开发,首先要引入 Compose 环境。Android Studio 新版可以直接创建 Compose 项目,但我当前的版本暂未提供这一功能。可以通过在 build.gradle 文件中添加相关依赖来引入 Compose。

公共基类

我创建了一个 BaseComposeActivity 作为 Compose 页面的公共基类,它继承自 AppCompatActivity,并在 onCreate 方法中使用 setContent 来设置 Compose UI。

基本布局

根据产品的原型图,我基于平板和手机做出了不同的响应式布局。只需通过 @Composable 函数来组合不同的组件,即可实现 Activity 显示不同的信息。

主页面逻辑

我注册了一个主页面 DevicePolicyActivity,在其中定义了基本布局并对平板和手机进行了区分。通过 TopBarRow 组件来安排导航栏和内容区域,使用 navigationNumberhideSelectTac 来控制不同的页面显示。

响应式布局
  • 平板端工作台:显示两列布局,左侧是目录,右侧是内容详情。
  • 非平板端工作台:基于页面跳转来显示详情页面。
策略目录菜单

目录菜单通过 DirectoryItemStrategyItem 组件来实现。通过点击菜单项更新选中状态,并相应地改变页面显示。对于非平板逻辑页面,点击后触发页面跳转,通过 forceRecompose 来手动触发页面重组。

DP根据逻辑生成的

这是ai根据我描述逻辑生成的,基本逻辑是一样的,但状态管理我都是基于remember和mutableIntStateOf进行管理的,其他意思到了就行:

代码实现细节

以下是基于 Compose 实现的核心代码逻辑和关键设计思路,结合具体场景进行说明:


1. BaseComposeActivity 基类
abstract class BaseComposeActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {MyAppTheme {  // 自定义主题配置AppContent() // 主 UI 入口}}}@Composableabstract fun AppContent()
}

设计要点:

  • 统一 Activity 入口模板
  • 强制子类实现 AppContent 方法作为 UI 入口
  • 集成 Material Design 主题系统

2. 主页面 DevicePolicyActivity 实现
class DevicePolicyActivity : BaseComposeActivity() {private val viewModel: PolicyViewModel by viewModels()@Composableoverride fun AppContent() {val isTablet = LocalConfiguration.current.screenWidthDp >= 600if (isTablet) {TabletLayout(viewModel)} else {PhoneLayout(viewModel)}}
}

设备检测逻辑:

@Composable
fun isTabletMode(): Boolean {val configuration = LocalConfiguration.currentreturn configuration.screenWidthDp >= 600 || configuration.smallestScreenWidthDp >= 600
}

3. 平板双栏布局实现
@Composable
private fun TabletLayout(viewModel: PolicyViewModel) {Scaffold(topBar = { AppTopBar(viewModel.selectedTitle) }) { padding ->Row(Modifier.padding(padding)) {// 左侧目录(占30%宽度)NavigationColumn(Modifier.weight(0.3f),viewModel.policies,viewModel::selectPolicy)// 右侧详情(占70%宽度)PolicyDetail(Modifier.weight(0.7f),viewModel.selectedPolicy)}}
}

关键交互逻辑:

// 状态管理示例
class PolicyViewModel : ViewModel() {private val _selectedPolicy = mutableStateOf<Policy?>(null)val selectedPolicy: State<Policy?> = _selectedPolicyfun selectPolicy(policy: Policy) {_selectedPolicy.value = policy}
}

4. 手机端列表-详情跳转
@Composable
private fun PhoneLayout(viewModel: PolicyViewModel) {val navController = rememberNavController()NavHost(navController, startDestination = "policyList") {composable("policyList") {PolicyListScreen(viewModel) { policy ->navController.navigate("policyDetail/${policy.id}")}}composable("policyDetail/{policyId}") { backStackEntry ->PolicyDetailScreen(policyId = backStackEntry.arguments?.getString("policyId"),onBack = { navController.popBackStack() })}}
}

5. 策略目录组件实现
@Composable
fun NavigationColumn(modifier: Modifier = Modifier,policies: List<Policy>,onSelect: (Policy) -> Unit
) {LazyColumn(modifier) {items(policies) { policy ->DirectoryItem(policy = policy,isSelected = policy == viewModel.selectedPolicy,onClick = { onSelect(policy) })}}
}@Composable
private fun DirectoryItem(policy: Policy,isSelected: Boolean,onClick: () -> Unit
) {Surface(color = if (isSelected) MaterialTheme.colors.primary.copy(alpha = 0.1f) else Color.Transparent,modifier = Modifier.fillMaxWidth().clickable { onClick() }) {Text(text = policy.title,modifier = Modifier.padding(16.dp),style = MaterialTheme.typography.subtitle1)}
}

6. 强制重组逻辑优化
// 使用 remember 配合 key 控制重组
var recomposeKey by remember { mutableStateOf(0) }LaunchedEffect(Unit) {// 当需要强制重组时recomposeKey++
}Column(modifier = Modifier.remember(recomposeKey) { /*...*/ }) {// 动态内容
}

替代方案:

// 使用 derivedStateOf 精细化控制
val filteredPolicies = remember(policies, searchQuery) {derivedStateOf {policies.filter { it.contains(searchQuery) }}
}

遇到的典型问题与解决方案

问题 1:状态更新未触发重组

现象: 修改 mutableStateOf 的值后 UI 未更新
解决方案:

// 错误写法
var count = mutableStateOf(0)
Button(onClick = { count.value++ }) // 正确写法
val count = remember { mutableStateOf(0) }
Button(onClick = { count.value++ })
问题 2:列表性能问题

现象: LazyColumn 滚动卡顿
优化方案:

items(policies, key = { it.id }) { policy ->// 使用稳定唯一的 key
}
问题 3:主题配置冲突

解决方案: 创建独立主题配置

@Composable
fun MyAppTheme(content: @Composable () -> Unit) {MaterialTheme(colors = darkColors(primary = Color(0xFFBB86FC),secondary = Color(0xFF03DAC6)),typography = MyTypography,content = content)
}

相关文章:

Jetpack Compose初体验

入门学习 由于工作需要&#xff0c;我们当前要在老代码的基础上使用 Compose 进行新页面的开发&#xff0c;这项工作主要落在我的身上。因此&#xff0c;我需要先了解 Compose。 这里我入门看的是写给初学者的Jetpack Compose教程&#xff0c;Lazy Layout&#xff0c;有兴趣可…...

ceph部署-14版本(nautilus)-使用ceph-ansible部署实验记录

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、环境信息二、部署步骤2.1 基础环境准备2.2 各节点docker环境安装2.3 搭建互信集群2.4 下载ceph-ansible 三、配置部署文件3.1 使用本地docker3.2 配置hosts…...

【C++】C++ 旅馆管理系统(含 源码+报告)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;专__注&#x1f448;&#xff1a;专注主流机器人、人工智能等相关领域的开发、测试技术。 系列文章目录 目录 系列文章目录一、设计要求二、设…...

快速排序

目录 什么是快速排序&#xff1a; 图解&#xff1a; 递归法&#xff1a; 方法一&#xff08;Hoare法&#xff09;&#xff1a; 代码实现&#xff1a; 思路分析&#xff1a; 方法二&#xff08;挖坑法&#xff09;&#xff1a; 代码实现&#xff1a; 思路分析&#xff1a; 非递…...

国内 ChatGPT Plus/Pro 订阅教程

1. 登录 chat.openai.com 依次点击 Login &#xff0c;输入邮箱和密码 2. 点击升级 Upgrade 登录自己的 OpenAI 帐户后&#xff0c;点击左下角的 Upgrade to Plus&#xff0c;在弹窗中选择 Upgrade plan。 如果升级入口无法点击&#xff0c;那就访问这个网址&#xff0c;htt…...

易仓科技ai面试

请解释PHP中的面向对象编程的基本概念&#xff0c;并举例说明如何在PHP中定义一个类。 回答思路&#xff1a;需理解类、对象、继承和多态等基本概念&#xff0c;并能通过实例代码展示如何定义类及其属性和方法。 . 类&#xff08;Class&#xff09; 类是一个封装了数据和操作…...

LabVIEW用户界面(UI)和用户体验(UX)设计

作为一名 LabVIEW 开发者&#xff0c;满足功能需求、保障使用便捷与灵活只是基础要求。在如今这个用户体验至上的时代&#xff0c;为 LabVIEW 应用程序设计直观且具有美学感的界面&#xff0c;同样是不容忽视的关键任务。一个优秀的界面设计&#xff0c;不仅能提升用户对程序的…...

字玩FontPlayer开发笔记14 Vue3实现多边形工具

目录 字玩FontPlayer开发笔记14 Vue3实现多边形工具笔记整体流程临时变量多边形组件数据结构初始化多边形工具mousedown事件mousemove事件监听mouseup事件渲染控件将多边形转换为平滑的钢笔路径 字玩FontPlayer开发笔记14 Vue3实现多边形工具 字玩FontPlayer是笔者开源的一款字…...

低代码与 Vue.js:技术选型与架构设计

在当下数字化转型的浪潮中&#xff0c;企业对应用开发的效率和质量有着极高的追求。低代码开发平台的兴起&#xff0c;为企业提供了一条快速构建应用的捷径&#xff0c;而 Vue.js 作为热门的前端框架&#xff0c;与低代码开发平台的结合备受关注。如何做好两者的技术选型与架构…...

比较循环与迭代器的性能:Rust 零成本抽象的威力

一、引言 在早期的 I/O 项目中&#xff0c;我们通过对 String 切片的索引和 clone 操作来构造配置结构体&#xff0c;这种方法虽然能确保数据所有权的正确传递&#xff0c;但既显得冗长&#xff0c;又引入了不必要的内存分配。随着对 Rust 迭代器特性的深入了解&#xff0c;我…...

一文了解zookeeper

1.ZooKeeper是什么 简单来说&#xff0c;她是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务 具体来说&#xff0c;他可以做如下事情&#xff1a; 分布式配置管理&#xff1a;ZooKeeper可以存储配置信息&#xff0c;应用程序可以动态读取配置信息。分布式同步&a…...

算法题(67):最长连续序列

审题&#xff1a; 需要我们在O&#xff08;n&#xff09;的时间复杂度下找到最长的连续序列长度 思路&#xff1a; 我们可以用两层for循环&#xff1a; 第一层是依次对每个数据遍历&#xff0c;让他们当序列的首元素。 第二层是访问除了该元素的其他元素 但是此时时间复杂度来到…...

大中型企业专用数据安全系统 | 天锐蓝盾终端安全 数据安全

天锐蓝盾系列产品是专门为大中型企业量身定制的数据安全防护产品体系&#xff0c;涵盖天锐蓝盾DLP、天锐蓝盾终端安全管理系统、天锐蓝盾NAC以及其他搭配产品&#xff0c;致力于实现卓越的数据安全防护、施行严格的网络准入控制以及构建稳固的终端安全管理体系。通过全方位的防…...

Deepseek解读 | UE像素流送与实时云渲染技术的差别

为了实现UE引擎开发的3D/XR程序推流&#xff0c;绝大多数开发者会研究像素流送&#xff08;Pixel Streaming&#xff09;的使用方法&#xff0c;并尝试将插件集成在程序中。对于短时、少并发、演示场景而言&#xff0c;像素流送可以满足基本需求。当3D/XR项目进入落地交付周期后…...

CTFSHOW-WEB入门-PHP特性109-115

题目&#xff1a;web 109 1. 题目&#xff1a; 2. 解题思路&#xff1a;题目要求获得两个参数&#xff0c;v1 v2&#xff0c;if语句中的意思是要求两个参数都包含字母&#xff0c;条件满足的话&#xff0c;执行 echo new 类名&#xff08;方法&#xff08;&#xff09;&#xf…...

模糊综合评价法:原理、步骤与MATLAB实现

引言 在复杂决策场景中&#xff0c;评价对象往往涉及多个相互关联的模糊因素。模糊综合评价法通过建立模糊关系矩阵&#xff0c;结合权重分配与合成算子&#xff0c;实现对多因素系统的科学评价。本文详细讲解模糊综合评价法的数学原理、操作步骤&#xff0c;并辅以MATLAB代码…...

【数据结构-红黑树】

文章目录 红黑树红黑树介绍红黑树的五个基本性质红黑树的平衡原理红黑树的操作红黑树的操作 代码实现节点实现插入和查询操作 红黑树 红黑树介绍 红黑树&#xff08;Red-Black Tree&#xff09;是一种自平衡的二叉查找树&#xff08;Binary Search Tree, BST&#xff09;&…...

【STM32】舵机SG90

1.舵机原理 舵机内部有一个电位器&#xff0c;当转轴随电机旋转&#xff0c;电位器的电压会发生改变&#xff0c;电压会带动转一定的角度&#xff0c;舵机中的控制板就会电位器输出的电压所代表的角度&#xff0c;与输入的PWM所代表的角度进行比较&#xff0c;从而得出一个旋转…...

【Linux】Socket编程—TCP

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;Linux系统编程 这里将会不定期更新有关Linux的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目…...

c++11 for auto不定参数

数量不定的模板参数。参数分为一个和一包两部分。 ​ 冒号的左边声明一个变量。右手边必须是一个容器。从容器(某种数据结构)中找出每一个元素设置到左边这个变量。11之前可以用容器的迭代器去取数据。或者标准库里的foreach...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...

React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?

系列回顾&#xff1a; 在上一篇《React核心概念&#xff1a;State是什么&#xff1f;》中&#xff0c;我们学习了如何使用useState让一个组件拥有自己的内部数据&#xff08;State&#xff09;&#xff0c;并通过一个计数器案例&#xff0c;实现了组件的自我更新。这很棒&#…...