Compose二三事:初步认识

news2025/2/24 1:34:17

Compose 是什么?

Compose是Jetpack系列中用于构建原生Android界面的工具库,Jetpack是Google推出的一系列帮助开发者规范代码的库。简单来说就是用代码写UI,也就是声明式UI

声明式UI和命令式UI的区别在于,声明式UI更关心做什么,而命令式UI关心怎么做。
简单来讲,我们直接使用View本身去显示内容,就是声明式,而我们要指定XML要去呈现什么内容,就是命令式。

写一个最简单的界面

下面用一个简单的界面对比一下Compose和常规的xml布局,这是一个非常简单的界面,如下。

在这里插入图片描述

我们常规的写布局的方式

  1. 定义布局文件
  2. 在Activity中引入
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Hello World!" />

</FrameLayout>

引入

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

如果用Compose来写

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .fillMaxHeight()
            ) {
                Text(
                    text = "Hello World!",
                    modifier = Modifier.align(Alignment.Center)
                )
            }
        }
    }
}

当然这样可能看起来比较臃肿,我们可以把布局部分独立出来。如下

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            mainContentView()
        }
    }
}

@Composable
fun mainContentView() {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .fillMaxHeight()
    ) {
        Text(
            text = "Hello World!",
            modifier = Modifier.align(Alignment.Center)
        )
    }
}

从以上可以看出:

  • Compose跟Flutter很像,如果有Flutter基础可基本上写Compose无压力
  • 布局逻辑清晰,入手难度不高

为什么要推进Compose?XML有什么问题?

为什么Android选择XML作为的布局语言

  • 可读性高:如果用代码写布局,很明显JAVA代码可读性非常差,布局逻辑非常不清晰
  • 与业务逻辑解耦:xml语言实现与java代码物理隔离

XML加载比较耗时

通过分析setContentView源码,可以得出XML加载是个非常耗时的操作。他的耗时来源于两个操作

  • 将布局文件加载到内存中:IO
  • 解析文件,生成对应的View:反射

当然我们可以避开这两个操作,有两种方式

  • AsyncLayoutInflater:异步加载,就是将IO和反射放到子线程去执行。
  • X2C:将布局文件在编译时转换成用JAVA代码写布局

AsyncLayoutInflater存在的问题是,他并没有解决掉布局加载耗时问题,即使放到了子线程,我们还是要等待布局加载完成,才能进行view的相关操作。

X2C存在的问题是,用JAVA写布局代码很不友好,而且很多属性不支持。

Compose 对比 XML

  • UI更加直观:从布局代码上来看,Compose的逻辑非常清晰,可以在Android Studio上实时预览,甚至可以在手机上实时刷新
  • 布局更加灵活:基于代码的布局方式,可以更方便的动态添加或修改布局,实现更复杂的UI效果
  • 更易于维护和修改:基于代码的布局文件,可以更方便的处理业务逻辑以及实现复用。省去了各种插件都想干掉的findviewbyid
  • 不需要手动更新:Compose的元素会对依赖的数据自动进行订阅,数据改变了,界面自动改变,不需要手动更新

在这里插入图片描述

使用代码写函数还有一个XML不能实现的效果

  Column {
        repeat(4) {
            log("repeat $it")
            Text(text = "Hello $it")
        }
    }

引入Compose

Compose基础配置

  • AS版本:Android Studio Arctic Fox 版本
  • Gradle:7.0 +
  • TargetSdk / CompileSdk:31 +
  • MinSdk:21 +
  • Kotlin:1.6.0+
  • Compose:1.1.1

实际配置

以下是项目引入Compose后实际的依赖情况

config.gradle

ext {
    android = [
            compileSdkVersion: 33,
            buildToolsVersion: "30.0.2",
        		...
    ]
  }

主module下build.gradle

	apply plugin: 'kotlin-kapt'
	...
  
    // 启用Jetpack Compose组件特性
    buildFeatures {
        compose true
    }

    composeOptions {
        kotlinCompilerExtensionVersion '1.1.0'
        kotlinCompilerVersion "1.1.1"
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }


dependencies {
    ...
    // Compose 库的主体包
    implementation 'androidx.compose.material:material:1.3.1'
    implementation "com.google.accompanist:accompanist-systemuicontroller:0.28.0"
    // 将 Activity 支持 Compose
    implementation 'androidx.activity:activity-compose:1.5.0'
    // Compose ui 预览
    implementation 'androidx.compose.ui:ui-tooling:1.1.1'
    implementation 'androidx.compose.ui:ui-util:1.3.3'
    // Compose ui 相关的基础支持
    implementation 'androidx.compose.ui:ui:1.1.1'
    // Compose 基于 ui 层封装的更实用的组件库 (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
    implementation 'androidx.compose.foundation:foundation:1.1.1'
    // Compose ViewModels 存储数据
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0'
    // Compose LiveData
    implementation 'androidx.compose.runtime:runtime-livedata:1.1.1'
}
	...

项目下build.gradle

...
buildscript {
    dependencies {
        ...
        classpath "com.android.tools.build:gradle:7.0.4"
				...
    }
}

gradle.properties

KotlinVersion=1.6.10

kotlin 升级后的问题

废弃了 ‘kotlin-android-extensions’ 插件。这个插件非常好用,可以直接通过id来引用View实例,但是他也存在一些问题

  • 销毁之后的空指针问题

KAE通过生成缓存解决findviewbyid问题,但是Activity的onDestory和Fragment的onDestoryView之后会清除缓存,这里导致的问题就是如果在这个生命周期时做一些view的操作,会出现空指针问题
如下代码会出现崩溃

import kotlinx.android.synthetic.main.activity_main.*
class MainFragment : Fragment() {
    ...

    override fun onDestroyView() {
        super.onDestroyView()

        textView.text = "Crash!"
    }
}

而下面不会

lateinit var textView: TextView

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    textView = view.findViewById(R.id.textView)
}

override fun onDestroyView() {
    super.onDestroyView()

    textView.text = "Nothing happened."
}

当然KAE也存在一些小问题,比如不存在的id等等,这些影响不大,还有个问题是它不支持Compose。我们可以使用viewbinding作为替代方案,它比KAE更安全

Gradle升级问题

  • maven依赖http的需要新增allowInsecureProtocol属性
        maven {
            url "..."
            allowInsecureProtocol = true
        }
  • 上传aar的方式变为publishing
...
apply plugin: 'maven-publish'

task androidSourcesJar(type: Jar) {
    archiveClassifier.set('sources')
    from android.sourceSets.main.java.srcDirs
}

publishing {
    repositories {
        maven {
            //文件发布到下面目录
            url = MAVEN_URL
            credentials {
                username MAVEN_USERNAME
                password MAVEN_PASSWORD
            }
        }
    }

    publications {
        aar(MavenPublication){
            groupId = groupId1
            artifactId artifactId1
            version versionName
            artifact androidSourcesJar
        }
    }
}

引入Compose的影响

  • 包体积:因为引入了新的库和依赖,所以会有所增加,不过Google的拆包都比较细,可以只引入需要的库。根据Google官方的统计,约会增加2~3M
  • 编译速度:Compose基于Kotlin编写,并且引入了一些新的编译工具和插件,对编译速度有一定的影响。不过如果使用构建缓存,编译速度影响不大,另外,Compose支持即时刷新界面

总结

Compose是未来Android的趋势,这是肯定的。但是他跟kotlin一样,不是一种“必须使用”的方案,他会逐步的替代XML,成为主流的开发方式。

仍需要跟进的问题

  • Compose的绘制原理是什么,Compose的Text和TextView区别在哪
  • Compose比XML快吗?

参考

使用 Jetpack Compose 更快地打造更出色的应用

Android Jetpack Compose —— 集成到现有项目中

要再见了吗,Kotlin Android Extension

扔物线compose

ChatGPT

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

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

相关文章

Python系列模块之标准库re详解

感谢点赞和关注 &#xff0c;每天进步一点点&#xff01;加油&#xff01; 目录 一、Python 正则表达式 1.1 re模块常用操作 1.2 re.match 1.3 re.search 1.4 re.findall 1.5 re.compile 函数 1.6 re.sub 检索和替换 1.7 re.split拆分 1.8 实战案例&#xff1a;根据文…

多看一眼多进步,python入门到放弃

python相关工具都安装完成后&#xff0c;就可以开始学习了&#xff0c;以下在pycharm中&#xff0c;以下学习内容来自b站边学习边整理的笔记&#xff0c;好记性不如赖笔头&#xff0c;多总结多记录&#xff0c;总是不错的 print()函数的使用 print函数可以输出哪些内容 &…

华为OD机试真题 Java 实现【优雅数组】【2023Q1 200分】

一、题目描述 如果一个数组中出现次数最多的元素出现大于等于k次&#xff0c;被称为k-优雅数组&#xff0c;k也可以被称为优雅阈值。 例如&#xff0c;数组[1, 2, 3, 1, 2, 3, 1]&#xff0c;它是一个3-优雅数组&#xff0c;因为元素1出现次数大于等于3次&#xff0c;数组[1,…

华为OD机试真题 Java 实现【取出尽量少的球】【2023Q1 200分】

一、题目描述 某部门开展 Family Day 开放日活动&#xff0c;其中有个从桶里取球的游戏。 游戏规则如下&#xff1a; 有 N 个容量一样的小桶等距排开&#xff0c;且每个小桶都默认装了数量不等的小球&#xff0c;每个小桶装的小球数量记录在数组 bucketBallNums 中。 游戏开…

eu.org申请免费域名 免费域名申请教程

EU.org是由Paul Mockapetris在1996年创建的免费域名服务&#xff0c;给没有资金买域名的个人或公司提供永久免费的域名。虽然是二级域名&#xff0c;但是已经被一些网络公司&#xff08;当然是国外的&#xff09;认定为顶级域名。 优缺点 优点&#xff1a;稳定性高、几乎没有…

04.Python Dash网页开发:ubuntu服务器部署DASH网站(uWSGI+nginx)

<~生~信~交~流~与~合~作~请~关~注~公~众~号生信探索> Dash官网只有付费的部署方式❌ 我的简单理解&#xff0c;uWSGI去运行dash app并且与nginx通讯&#xff1b;nginx处理浏览器传来的请求并把需求给uWSGI Python enviroment mkdir bioquestvi ~/bioquest/dash.yamlmicro…

docker搭建简单elk日志系统6(kibana设置)

1.进入kibana的索引管理界面清理调之前生成的测试数据流 2.模拟dev、uat、prod三个环境产生日志 修改filebeat配置文件&#xff0c;重启filebeat fields: application: testenv: devlog_type: normalfilebeat -c .\filebeat-test.yml产生日志 查看kibana数据流(已经生成dev环…

C++11 -- 类的新功能

文章目录 类的新功能默认成员函数类成员变量初始化强制生成默认函数的关键字default禁止生成默认函数的关键字delete继承和多态中的final和override关键字 类的新功能 默认成员函数 原来在C类中,有6个默认成员函数: 1: 构造函数 2: 拷贝构造函数 3: 拷贝赋值重载 4: 析构函数…

mysql 索引有哪几种?主键索引、唯一索引

面试题&#xff1a;mysql索引有哪几种&#xff1f; 答&#xff1a; 索引有两类&#xff0c;一是单列索引&#xff0c;二是组合索引。 单列索引&#xff0c;即一个索引只包含单个列&#xff0c;一个表可以有多个单列索引&#xff0c;但这不是组合索引。组合索引&#xff0c;即一…

SQL查询语言(3) 聚集查询和窗口函数的概念

查询结果排序 排序 规则如下: 1.语句: SELECT A1,A2.... FROM 表名 WHERE 选择条件 order by 属性1(ASC升序),属性3(DESC降序); 如果没有说明默认是升序排列: 2.对于空值的处理 如果是升序排列 NULL放在最后一行&#xff0c;如果是降序则放在第一行 上图为 按升序排列查询…

MyBatis动态SQL,基本语法加实战,一篇搞懂

问题&#xff1a; 有的时候我们需要实现批量删除&#xff1a;delete from t_car where id in(1,2,3,4,5,6,…这⾥的值是动态的&#xff0c;根据⽤户选择的 id不同&#xff0c;值是不同的); 多条件查询:有时我们需要根据多个不同地条件来进行查询&#xff0c;比如&#xff1a;se…

数据集成平台之kettle优缺点分析

数据集成平台前言 数据在业务中发挥着重要的作用&#xff0c;但并非所有数据都具有相同的价值和影响力。事实上&#xff0c;大部分数据业务的核心价值主要来自其中的少部分关键数据。这些关键数据可能包含着重要的业务指标、关键客户信息、市场趋势数据等&#xff0c;它们直接…

【机器学习】之Anaconda中使用的命令

操作之前&#xff0c;点击上图入口&#xff0c;进入Prompt。 //示例是在base环境下&#xff0c;cls清屏 (base) C:\Users\bubusa>cls1、base环境下的操作 //&#xff08;1&#xff09;列出所有虚拟环境 (base) C:\Users\bubusa>conda env list # conda environments: #…

Radeon Vii 系统分析 001记——工具

0. 简介 为了对 vega 7nm 有更感性的编程使用体验&#xff0c;故对 vega 7nm做各种测试&#xff1b; 工具&#xff1a; CLRadeonExtender ubuntu ROCm 资料&#xff1a; &#xff08;1&#xff09; 一张安装了 Radeon Vii vega 7nm 的台式机&#xff0c;win10 或 ubunt…

Mit6.006-lecture08-BinaryHeaps

一、优先队列接口 记录一些项目&#xff0c;快速地访问/移除最重要的 例&#xff1a;有限带宽的路由器&#xff0c;必须优先某些信息 例&#xff1a;操作系统内核中的进程调度 例&#xff1a;离散事件模拟&#xff08;下一件事何时发生&#xff09; 例&#xff1a;图算法&am…

js程序运行时在本机与外部app交互

js程序运行时在本机与外部app交互 目录 js程序运行时在本机与外部app交互 一、序言 1.1、问题 1.2、简要回答 二、原理 2.1、插件/web扩展/应用配置/权限 2.2、获取权限-原生应用交换信息的权限nativeMessaging 2.2.1、runtime(运行时的API) 2.3、连接本地应用程序的…

《微服务实战》 第十四章 RabbitMQ应用

前言 一般MQ用于系统解耦、削峰使用,常见于微服务、业务活动等场景。 1、RabbitMQ概念概念 RabbitMQ整体上是一个生产者与消费者模型,主要负责接收、存储和转发消息。 1.1、生产者和消费者 Producer:生产者,就是投递消息的一方。消息一般可以包含2个部分:消息体和标签…

Vue3+i18n多语言动态国际化设置步骤

1、技术介绍 i18n&#xff1a;Vue.js 的国际化插件。它可以轻松地将一些本地化功能集成到你的 Vue.js 应用程序中 i18n的官网地址安装 | Vue I18n (kazupon.github.io) 2、插件安装 npm install vue-i18n9 --save需要注意的是vue3最好使用9.x以上的版本&#xff01; 3、创建i…

夏日挂脖风扇方案开发设计

夏日挂脖风扇是一种便携式的风扇设备&#xff0c;通过挂在用户的脖子上&#xff0c;为用户提供清凉的风力降温。在夏季高温天气中&#xff0c;挂脖风扇成为了人们追逐的热门产品之一。为了满足市场需求&#xff0c;夏日挂脖风扇的方案开发设计需要考虑多个方面&#xff0c;包括…

Class 09 - Data Frame和查看数据

Class 09 - Data Frame和查看数据 DataFrametibbleshead()str()colnames()mutate()创建 Dataframe DataFrame 在我们开始做数据清洗或者检查数据是否存在偏差之前&#xff0c;我们需要先将我们的数据转换成合适的格式方便我们做后续的处理。 这就要说到DataFrame了。因为他很…