快速入门KMM和Compose Multiplatform

news2024/11/18 6:48:50

一、前言

最近才有空,想起来Compose-jb和kmm这2个框架,就来个快速入门指南吧。

什么是KMM (Kotlin Multiplatform Mobile)

KMM用于简化跨平台开发,可以在Android和IOS之间共享通用的代码。
仅在使用各自平台能力的时候,才会去编写各自平台特定的代码。

Compose Multiplatform, by JetBrains 缩写名称:compose-jb

Compose Multiplatform, by JetBrains

JetBrains开源的compose-jb官方的介绍内容:

桌面和Web UI框架,基于Google的JetpackCompose工具包
Compose Multiplatform 简化并加速了桌面和Web应用程序的UI开发,并且允许Android和桌面之间大部分的UI代码共享。

二、Window平台-开发工具

1、compose-jb环境安装

1、下载IntelliJ IDEA Community Edition

2、下载JAVA JDK

2、KMM环境安装

1、下载AndroidStudio

2、下载JAVA JDK

3、下载Kotlin多平台移动插件

在Android Studio中,在市场中搜索:Kotlin Multiplatform Mobile,然后安装

在这里插入图片描述

4、更新Kotlin插件

Kotlin插件与AndroidStudio版本是捆绑在一起的,我们需要更新Kotlin到最新版本,来避免兼容性问题。
在这里插入图片描述

三、MacOS平台-开发工具

1、compose-jb环境安装

1、下载IntelliJ IDEA Community Edition

2、下载JAVA JDK

2、KMM环境安装

1、下载XCode

2、在终端或命令行工具中,运行以下命令

brew install kdoctor

如果你还没有Homebrew,请安装它或查看KDoctor README以获取其他安装方法。

3、安装完成后,在控制台调用 KDoctor

kdoctor

四、KMM工程

1、创建工程

打开AndroidStudio ,点击 New Project,然后找到 Kotlin Multiplatform App,然后点击 Next

在这里插入图片描述

配置应用程序的名称、应用包名、项目的位置、最小SDK版本,配置完成之后,点击 Next

在这里插入图片描述

iOS framework distribution 我们选择Regular framework, 因为此选项不需要第三方工具,并且安装问题较少。

cocoapods dependency manager 是什么呢?

CocoaPods是 Swift 和 Objective-C Cocoa项目的依赖管理器。

对于更复杂的项目,可能需要CocoaPods依赖项管理器来帮助处理库依赖项。

在这里插入图片描述

点击Finish,首次执行此操作时,下载和设置所需的组件可能需要一些时间。

2、工介绍

KMM工程包含三个模块:

  • androidApp 是Android应用程序项目,依赖于shared模块,并将shared模块用作常规的Android库,UI就是使用Jetpack Compose那一套

  • shared 包含Android和iOS应用程序在平台之间共享的通用代码逻辑

  • iosApp 是iOS应用程序项目,它依赖于并使用shared模块作为iOS框架

在这里插入图片描述
androidApp和iosApp模块都是各自平台原来的开发方式,shared模块它是平台之间共享的通用代码逻辑,那么它如何实现共享的呢?我们看一下下面这张图片:
在这里插入图片描述

连接到各自的平台:

expect和actual文档

我们可以看到它在公共模块中使用expect关键字,expect修饰类、成员变量或方法时,表示类、成员变量、方法,可以跨平台实现。

注意:expect声明不包含任何实现代码。
expect和actual所修饰的类/变量/方法,名称都需要完全一样,并且位于同一包中(具有相同的完整包名)。

在各自的平台Android/IOS,中使用actual修饰,实现同名的类、方法、成员变量。

我们再来看Hello World示例,commonMain目录下面创建了一个Platform接口,并使用expect关键字修饰了getPlatform()方法
在这里插入图片描述

那么Android/IOS平台,需要去使用actual修饰,实现同名的类、方法、成员变量。
在这里插入图片描述

我们在commonMain目录下面,可以定义逻辑类,共享通用的代码逻辑,同样以Hello World为例:
在这里插入图片描述

那么在Android/IOS的工程中就可以使用这个Greeting类来获取通用的代码逻辑,如下:

在这里插入图片描述


在这里插入图片描述

3、如何添加依赖项

切换到Project视图下,找到shared模块,点击build.gradle.kts,在sourceSets里面,我们可以给
commonMain、androidMain、iosMain 分别添加依赖。

我们这里给commonMain添加依赖项,这样Android、IOS平台就可以在获取通用代码逻辑的时候,使用到这个依赖项的能力了。

在这里插入图片描述

添加kotlinx-datetime的依赖项:

kotlin {
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
            }
        }
    }
}

在这里插入图片描述

commonMain目录下面创建一个KotlinNewYear.kt的File:

import kotlinx.datetime.*

fun daysUntilNewYear(): Int {
    val today = Clock.System.todayIn(TimeZone.currentSystemDefault())
    val closestNewYear = LocalDate(today.year + 1, 1, 1)
    return today.daysUntil(closestNewYear)
}

我们在Greeting里面使用这个方法:
在这里插入图片描述

我们看看运行之后的结果:

4、网络请求

我们需要准备以下三个多平台库

  • kotlinx.coroutines,用于使用协程编写异步代码,允许同时操作
  • kotlinx.serialization,用于将 JSON 响应反序列化为用于处理网络操作的实体类的对象。
  • Ktor,一个作为HTTP客户端的框架,用于通过互联网检索数据。

1、添加Kotlinx.coroutines依赖库:

在shared模块的build.gradle.kts中,添加kotlinx.coroutines依赖

sourceSets {
    val commonMain by getting {
        dependencies {
            // ...
           implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
        }
    }
}

我们打开项目根目录下面的build.gradle.kts文件,查看kotlin版本是否小于1.7.20

在这里插入图片描述

使用 Kotlin 1.7.20 及更高版本,则默认情况下已经启用了新的 Kotlin/Native 内存管理器。

Kotlin版本小于1.7.20版本,请将以下内容添加到build.gradle.kts文件末尾:

kotlin.targets.withType(org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget::class.java) {
    binaries.all {
        binaryOptions["memoryModel"] = "experimental"
    }
}

2、添加Kotlinx.serialization依赖库:

我们打开shared模块,打开build.gradle.kts文件,在文件开头的plugins块中增加 序列化插件 内容:

在这里插入图片描述

plugins {
    kotlin("plugin.serialization") version "1.8.0"
}

3、添加Ktor依赖库

我们打开shared模块,打开build.gradle.kts文件,增加下面内容:

val ktorVersion = "2.2.1"

sourceSets {
    val commonMain by getting {
        dependencies {
            // ...
            implementation("io.ktor:ktor-client-core:$ktorVersion")
            implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
            implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
        }
    }
    val androidMain by getting {
        dependencies {
            implementation("io.ktor:ktor-client-android:$ktorVersion")
        }
    }
    val iosMain by creating {
        // ...
        dependencies {
            implementation("io.ktor:ktor-client-darwin:$ktorVersion")
        }
    }
}

ktor-client-core:核心依赖项。

ktor-client-content-negotiation:负责序列化/反序列化特定格式的内容。

ktor-serialization-kotlinx-json:使用JSON格式用作序列化库,在接收响应时将其反序列化为数据类。

ktor-client-android:提供Android平台引擎

ktor-client-darwin:提供IOS平台引擎

点击Sync Now同步Gradle之后,我们创建一个RocketLaunch.kt

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class RocketLaunch (
    @SerialName("flight_number")
    val flightNumber: Int,
    @SerialName("name")
    val missionName: String,
    @SerialName("date_utc")
    val launchDateUTC: String,
    @SerialName("success")
    val launchSuccess: Boolean?,
)

点击查看Ktor官方文档

4、创建一个Ktor实例来执行网络请求并解析生成的JSON

import io.ktor.client.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json

class Greeting {
    private val platform: Platform = getPlatform()

    private val httpClient = HttpClient {
        // 安装ContentNegotiation插件
        install(ContentNegotiation) {
            // 注册 JSON 序列化程序
            json(Json {
                // true:表示打印并生成漂亮的JSON。 默认情况下:false
                prettyPrint = true
                // true:删除 JSON 规范限制,允许使用带引号的布尔文本和不带引号的字符串文字
                isLenient = true
                // true:表示可以忽略JSON中遇到的未知属性,防止引发序列化异常。 默认情况下:false
                ignoreUnknownKeys = true
            })
        }
    }
}

点击查看ContentNegotiation Ktor插件文档

修改greeting方法,添加suspend修饰,并使用httpClient去获取网络请求的数据:

import io.ktor.client.call.*
import io.ktor.client.request.*

class Greeting {
    // ...
    @Throws(Exception::class)
    suspend fun greeting(): String {
        // 获取数据
        val rockets: List<RocketLaunch> =
            httpClient.get("https://api.spacexdata.com/v4/launches").body()
        // 判断最近一次火箭是否发射成功
        val lastSuccessLaunch = rockets.last { it.launchSuccess == true }
        // 返回结果
        return "Guess what it is! > ${platform.name.reversed()}!" +
                "\nThere are only ${daysUntilNewYear()} left until New Year! 🎆" +
                "\nThe last successful launch was ${lastSuccessLaunch.launchDateUTC} 🚀"
    }
}

到这里还没结束,这里只是获取数据的代码,Android/IOS项目目录下面,仍然要配置内容,请往下看:

5、Android相关配置

  • 打开androidApp/src/main/AndroidManifest.xml 配置网络权限:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.jetbrains.simplelogin.kotlinmultiplatformsandbox" >
    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>
  • 打开androidApp/build.gradle.kts 添加Android协程库,处理commMain模块的挂起方法:

在这里插入图片描述

dependencies {
    // ..
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")
}

然后点击同步Gradle,打开MainActivity.kt文件,使用协程调用suspend fun greeting()

import androidx.compose.runtime.*
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApplicationTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    val scope = rememberCoroutineScope()
                    var text by remember { mutableStateOf("Loading") }
                    LaunchedEffect(true) {
                        scope.launch {
                            text = try {
                                Greeting().greeting()
                            } catch (e: Exception) {
                                e.localizedMessage ?: "error"
                            }
                        }
                    }
                    GreetingView(text)
                }
            }
        }
    }
}

6、IOS相关配置

IOS这里使用SwiftUI构建UI界面,使用Model-view-ViewModel,将 UI 连接到包含所有业务逻辑的shared模块

ContentView.swift中创建viewModel,并获取shared模块中的网络请求数据:

看到这里可能大家都会感觉很熟悉,鸿蒙的ArkUI和SwiftUI真的好像,感觉就是表兄弟。
Compose和SwitfUI还差点样子,样貌算是外甥的那种哈哈。

在这里插入图片描述

点击查看DispatchQueue.main.async解释

运行之后AndroidIOS的界面显示如下:

5、小结

KMM属于Android和IOS各自写各自平台的UI,通用的业务逻辑数据处理需要从shared模块去获取。
优点:重复的业务逻辑数据处理部分,统一处理,在业务需求发生变更,也只需要更新shared模块即可,Android/IOS各自平台只需要关心各自的UI和平台的细节处,分工合作。
缺点:不能统一平台UI,各自平台仍然要每个平台各自写一份,但是总提上来说还是减少了一定的工作量。

点击观看官方KMM技术演进的计划-视频源自youtube

点击观看官方KMM技术演进的计划-视频源自Bilibili

五、Compose-jb工程

在这里插入图片描述

我们从上面可以看到创建单平台的项目,目前可以选择DesktopWeb

1、单平台Desktop目录介绍

创建一个单平台Desktop项目,项目目录如下:
在这里插入图片描述

jvmMain目录下面编写我们的窗口代码,build.gradle.kts文件中,我们需要在sourceSetsjvmMain中添加我们的三方库依赖:

    sourceSets {
        val jvmMain by getting {
            dependencies {
                // 增加其他依赖库
                implementation(compose.desktop.currentOs)
            }
        }
        //.....
    }

build.gradle.kts文件中最后,这段代码,里面的内容有啥含义呢?


// 包名
group = "com.example"
// 应用程序的版本名称
version = "0.1-SNAPSHOT"

compose.desktop {
    application {
        // 程序入口类
        mainClass = "MainKt"
        nativeDistributions {
            // 目标格式
            targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
            // 应用程序的名称
            packageName = "demo"
            // 安装包版本名称
            packageVersion = "1.0.0"

            // 下面是我用来介绍元数据增加的,仅供参考
            // 应用程序描述(默认值:无)
            description = "Compose Example App"
            // 应用程序的版权(默认值:无)
            copyright = "© 2023 My Name. All rights reserved."
            // 应用程序的供应商(默认值:无)
            vendor = "Example vendor"
            // 应用程序的许可证(默认值:无)
            licenseFile.set(project.file("LICENSE.txt"))
        }
    }
}

更多使用细节,可参考github这里的README.md文档

打开gradle.properties文件,可修改kotlin、agp、compose版本号:

在这里插入图片描述

打开settings.gradle.kts文件,可修改配置maven仓库镜像地址,以及插件版本号

在这里插入图片描述


这里注意一点,如果你不看参数注释直接去修改 Window 窗口透明的话:

// 错误的用法
fun main() = application {
    Window(onCloseRequest = ::exitApplication, transparent = true) {
        App()
    }
}

运行的时候,会提示如下错误:

Exception in thread "main" java.lang.IllegalStateException: Transparent window should be undecorated!

............

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':run'.
> Process 'command '************\bin\java.exe'' finished with non-zero exit value 1

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.

* Get more help at https://help.gradle.org

修改后的窗口透明代码如下:

fun main() = application {
    // undecorated - 禁用或启用此窗口的装饰。
    // transparent - 禁用或启用窗口透明度。只有在窗口【没有启用装饰】时才应设置透明度,否则将抛出异常。
    Window(onCloseRequest = ::exitApplication, undecorated = true, transparent = true) {
        App()
    }
}

运行起来之后,整个窗口背景色都是透明的,但窗口实际占的位置还是原来那么大(占位的部分,不能点击穿透),我用红色方框画了窗口的实际大小,如下:
在这里插入图片描述

2、单平台Web目录介绍

在这里插入图片描述

先看一下index.html文件的内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sample</title>
</head>
<body>
<div id="root"></div>
<script src="替换成你的module名称.js"></script>
</body>
</html>

很普通,body最后一行,需要引入以ModuleName为名称的js文件,还定义了一个div root用来插入Compose管理的DOM树内容。

我们再打开Main.kt文件,在main()方法里面,入口是这样使用的:

renderComposable(rootElementId = "root") {
    // 内容在这里
}

Compose需要一个根节点,用来管理自己的DOM树:

fun renderComposable(
    rootElementId: String,
    content: @Composable DOMScope<Element>.() -> Unit
): Composition = renderComposable(
    root = document.getElementById(rootElementId)!!,
    content = content
)

这里的root,是通过document.getElementById(rootElementId)获取的,这个方法的作用是:

返回一个Element对象,用于快速访问:id为root的div元素。

通过Compose DOM DSL给我们提供的常用的HTML可组合项,我们可以在renderComposable里面使用它们,
TextSpanDivInputATextArea 等等可组合项。

查看可组合项和HTML标签代码的异同:

Span(
    attrs = { style { color(Color.red) } } // inline style
) {
    Text("Red text")
}

对应的HTML代码:

<span style="color: red;">Red text</span>

可运行下面示例查看简单的界面:

import androidx.compose.runtime.*
import org.jetbrains.compose.web.attributes.*
import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.dom.*
import org.jetbrains.compose.web.renderComposable

fun main() {
    var count: Int by mutableStateOf(0)

    renderComposable(rootElementId = "root") {
        val text = remember { mutableStateOf("") }
        TextArea(
            value = text.value,
            attrs = {
                onInput {
                    text.value = it.value
                }
            }
        )
        Div({ style { padding(25.px) } }) {
            Button(attrs = {
                onClick { count -= 1 }
            }) {
                Text("-")
            }

            Span({ style { padding(15.px) } }) {
                Text("$count")
            }

            Button(attrs = {
                onClick { count += 1 }
            }) {
                Text("+")
            }
        }

        A(
            attrs = {
                href("https://www.baidu.com")
                target(ATarget.Blank)
                hreflang("en")
                download("https://...")
            }
        ) { Text("打开百度的超链接") }
    }
}


那么如何运行Web项目到浏览器中呢?

我们可通过命令,或者通过工具栏菜单去运行:

./gradlew jsBrowserRun

如果不想每次变更内容都去重新编译和运行,可通过如下命令连续编译模式:

./gradlew jsBrowserRun --continuous

或者通过IDEA的工具栏去双击运行它:

在这里插入图片描述

运行之后,浏览器将打开:localhost:8080 界面如下:

点击查看Compose-Web详细使用的文档指南

3、多平台目录介绍

在这里插入图片描述

切换到多平台去创建一个工程,创建完工程,我们看一下目录图片(可保存到电脑上查看长图):

我们发现这个多平台的目录,只有AndroidDesktop平台,那么接着往下看吧:

androiddesktop,把可组合项代码放到了commonMain目录下面,意味着AndroidDesktop 能共用可组合项代码了,一模一样肯定是不能够的,我们要根据platform区分,因为电脑桌面的UI和手机UI排列和样式这些还是会不同的。

1、运行桌面应用

./gradlew :desktop:run

2、构建桌面应用发布包(JDK>=15)

./gradlew :desktop:packageDistributionForCurrentOS

或者可以通过菜单栏去双击构建运行:

3、运行Android应用

点击IDE的Edit Configurations,去配置一个Android app

然后在工具栏上面,菜单栏下面,有如下入口,可点击按钮运行:

4、打包Android APP

命令打包:

./gradlew build release

或者通过菜单项,手动点击去打包,Build -> Generate Signed Bundle/Apk

4、小结

Compose Multiplatform 加速了桌面和Web应用程序的UI开发,创建多平台的项目工程的时候,Android和桌面之间大部分的UI代码可直接共享。

目前看还有很长的路要走,期待:IOS工程能像Android和Desktop一样共享大部分UI代码。

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

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

相关文章

解决前端组件渲染没更新数据问题

问题&#xff1a; 使用前端日期控件时 - 数据联动时数据绑定无效问题 现象&#xff1a; 选择A日期&#xff0c;想动态改变B日期数据&#xff0c;只有第一次选择时会动态改变B日期数据&#xff0c;第二次选择A日期时&#xff0c;B日期数据虽已改变&#xff0c;但是页面数据未改变…

电子邮件备份软件:Email Backup Wizard Crack

适用于所有用户的电子邮件备份软件 在您的计算机、台式机或硬盘驱动器上本地创建您的电子邮件帐户的备份。 下载并保存电子邮件以备后用。 如果您想备份和移动服务器电子邮件&#xff0c;请尽快获取备份工具。 通过简单直观的功能获得强大的结果 苹果系统邮箱备份向导 - 批量下…

C++ · 类和对象 · 03 | 深化理解

啊我摔倒了..有没有人扶我起来学习.... &#x1f471;个人主页&#xff1a;《CGod的个人主页》\color{Darkorange}{《CGod的个人主页》}《CGod的个人主页》交个朋友叭~ &#x1f492;个人社区&#xff1a;《编程成神技术交流社区》\color{Darkorange}{《编程成神技术交流社区》…

Python tkinter -- 第18章 画布控件之椭圆

**18.2.18 create_oval(bbox, options) 根据限定矩形 bbox 在画布上创建一个椭圆。 &#xff08;1&#xff09;bbox&#xff1a;定义要创建对象的边界(x1, y1, x2, y2) &#xff08;2&#xff09;options:创建椭圆的选项。选项的具体含义&#xff1a; 选项含义activedash当鼠标…

微信小程序+前端+天行数据垃圾图像识别接口API

文章目录 前言 步骤 1. 去到天行数据官网注册账号&#xff0c;去到接口的介绍网站 2. 去测试网站&#xff0c;先看看请求的格式 3. 小程序端我采用的是把网站上的url链接的网络图片转成base64编码后的形式作为传入参数&#xff0c;这里需要有点基础&#xff0c;因为只给上了…

JVM基础 - 类加载的过程

类加载的过程加载验证准备解析初始化使用卸载其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中&#xff0c;加载、验证、准备和初始化这四个阶段发生的顺序是确定的。而解析阶段则不一定&#xff0c;它在某些情况下可以在初始化阶段之后开始&…

RFID技术在生产企业的集成应用分析

RFID技术在生产企业的集成应用分析1.RFID的主要功能RFID自动识别功能RFID标签的主要核心部件是一个电子芯片&#xff0c;芯片中存储着能够识别目标的信息。RFID标签具有持久性、信息接收传播穿透性强、存储信息容量大、种类多等特点。有些RFID标签支持读写功能&#xff0c;目标…

CHAPTER 15 Mesos(一)

Mesos-优秀的集群资源调度平台15.1 Mesos简介15.2 Mesos安装与使用1. 安装1. 源码编译2. 软件源安装3. Docker方式安装2. 配置说明1. ZooKeepr2. Mesos3. Marathon3.访问Mesos图形界面4.访问Marathon图形界面1. 通过界面方式2. REST API方式15.3 原理与架构1. 架构2. 基本单元3…

CentOS7中安装Hadoop3详细步骤

目录 (一)新建一个虚拟机 (二)配置网络 (三)安装vim工具 (四)设置ssh免密登录 (五)设置时间同步 (六)修改主机名 1.方法一 2.方法二 (七)给主机文件添加IP名称映射 (八)安装JDK8 (九)安装Hadoop 1.打开Xftp&#xff0c;连接虚拟机&#xff0c;在/opt目录下新建两个…

[引擎开发] 现代图形API - metal篇

Metal是苹果开发的图形计算接口&#xff0c;它是在移动端出现的比较早的现代图形API。本文将更侧重于移动端&#xff08;IOS&#xff09;&#xff0c;对metal的API做一个大致的引入介绍。 Apple GPU概述 在我们对Metal进行介绍前&#xff0c;先来了解一下Apple GPU。 Apple GP…

Linux常用命令——printf命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) printf 格式化并输出结果 补充说明 printf命令格式化并输出结果到标准输出。 语法 printf(选项)(参数) --help&#xff1a;在线帮助&#xff1b; --version&#xff1a;显示版本信息。参数 输出格式&#x…

第1讲 谈谈你对Java平台的理解?

第1讲 | 谈谈你对Java平台的理解&#xff1f; 从你接触 Java 开发到现在&#xff0c;你对 Java 最直观的印象是什么呢&#xff1f;是它宣传的 “Write once, run anywhere”&#xff0c;还是目前看已经有些过于形式主义的语法呢&#xff1f;你对于 Java 平台到底了解到什么程度…

《你不会还没入门jvm调优吧》之前置知识

该文章为科普文&#xff0c;所以很多细节涉及不到&#xff0c;旨在指引入门&#xff0c;同事在聊的时候不至于插不上话&#xff0c;顺带回顾部分JVM相关知识。准备好了吗&#xff0c;开始发车。如有不正确的地方&#xff0c;欢迎批评指正。 目录 JVM调优调的到底是什么 回顾…

Linux(CentOS 7)--gdb的基本调试指令

一下面的代码为例介绍一下linux中&#xff0c;gdb调试的基本指令 创建一个文件myfile.c&#xff0c;文件代码内容如下 1 #include <stdio.h>2 3 int Add(int x, int y)4 {5 6 return xy; …

高性能消息队列中间件MQ_part2

接上一篇part1的内容 RabbitMQ通配符模式_编写消费者 接下来我们编写通配符模式的消费者&#xff1a; // 站内信消费者 public class Customer_Station {public static void main(String[] args) throws IOException, TimeoutException {// 1.创建连接工厂ConnectionFactory…

springboot引入flink,maven打包插件需替换

目录说明说明 springboot引入flink后&#xff0c;如果要打包&#xff0c;传统的maven不行&#xff0c;要更换指定插件 <build><finalName>flink</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><art…

CMake 混编c和c++代码

准备工作 wsl 或者 有linux 系统(购买阿里云或者其他云服务器&#xff09;cmake, gcc, git 等一些必要的软件安装 环境 windows 下 的 wsl wsl 安装下载 例子 拿 Unix网络编程 举例, 作者对原生接口进行了封装, 我们需要编译使用在自己的工程 1. 创建空文件 cd E:\githu…

网络流量监控对OA系统性能分析案例

需求简介 某外高桥公司的OA系统是其重要的业务系统&#xff0c;OA系统负责人表示&#xff0c;部分用户反馈&#xff0c;访问OA系统时比较慢。需要通过分析系统看一下实际情况。 报告内容 本报告内容主要为&#xff1a;OA性能整体分析 分析时间 报告分析时间范围为&#xf…

同一条好友邀请信息给大量的人发,会导致领英账号被封吗?

做外贸的领英新人经常有一个问题&#xff1a;领英上添加好友时&#xff0c;同一条好友邀请信息给大量的人发&#xff0c;会导致领英账号被封吗&#xff1f; 这是一个被一部分人所忽略&#xff0c;也在被一部分人所担心的问题&#xff0c;因为很多领英新手都是在复制粘贴发送相…

游戏开发者的视觉盲区

本文首发于微信公众号&#xff1a; 小蚂蚁教你做游戏。欢迎关注领取更多学习做游戏的原创教程资料&#xff0c;每天学点儿游戏开发知识。嗨&#xff01;大家好&#xff0c;我是小蚂蚁。前天我刚发布了一个新的游戏作品——经典宝石方块。仍然是掌机模式&#xff0c;仍然是简约风…