Skip to content

Kotlin Multiplatform Compose简单教程

更新: 2/25/2026 字数: 0 字 时长: 0 分钟

Kotlin Multiplatform Compose是Jetbrain基于现有的Google Jetpack Compose进行二次开发的用于Kotlin Multiplatform的UI框架,其希望可以使用原本Jetpack Compose的开发方式来对KMP的所有端进行UI绘制,底层基于Skia框架进行UI层面的渲染。

声明式 VS 命令式

早年间Android开发是基于XML,这种命令式的开发在现代编程中显得过于落后,目前主流的前端开发框架(Vue/React)均采用的声明式的开发模式,因此Google也希望自己的系统应用也能使用这种高效的开发方式

基于这种情况,Google开发了Jetpack Compose,希望取代原本的XML作为Android端开发的主流方式

所谓的声明式,即变量与UI深度绑定

kotlin
Text(text)

在上述文本中,变量text如果变化,Text组件也会随之改变,这就是所谓的声明式编程方式,即将变量声明后,组件的内容就会和声明的变量进行绑定

基于原本的Kotlin体系下,Compose使用的是mutableStateOf函数来实现的声明式

kotlin
val text=mutableStateOf("Hello Compoes")
Text(text.value)

在这种情况下,Text的值会完全跟着text的变化而变化

状态

上文中的stateOf的变量就是Compose中的状态,我们通过mutableStateOf方法很简单的创建出来了一个状态

当状态变化时,Compose就会发生页面的刷新,而刷新则分为:组合(Composition),布局,绘制,三个过程

  • Composition:执行Compose代码(@Composable)的过程,这一过程完成了界面实际内容的拼凑
  • 布局:针对用户界面进行测量,将拼凑出的Compose对象进行放置
  • 绘制:将布局好的Compose对象绘制出用户可以看到的样子

这里需要特别说明的是,Composition过程中执行的动作被称为Compose,Compose的具体操作就是使用我们的Composable函数生成出一些对象,我们后续的布局和绘制用的都是这些对象,所以我们也可以理解为Composable函数并不是实际的界面元素,而是用来生成实际的界面元素的,这也解释了为什么Compose中是依赖函数来完成代码编写的

当状态被Compose组件绑定后,状态的变化会直接导致界面的重组

kotlin
var show by remember { mutableStateOf(false) }  
  
var size by remember { mutableStateOf(1) }  
  
Column {  
    if (show){  
        Text("You Can Look Me")  
    }  
  
    Button(  
        modifier = Modifier  
            .height((size*50).dp)  
            .width((size*150).dp),  
        onClick = {  
	        show = true  
	        size++  
     }) {  
        Text("This is a Button")  
    }  
  
    LaunchedEffect(Unit){  
        delay(3000)  
        show=false  
    }  
}

以上述代码为例,我们的状态有show和size两个变量,这两个状态可以直接影响到界面的变化,因为他们与Compose函数发生了绑定关系,因此这些状态的值发生变化时,相关的组件都会发生重组

对于创建一个状态,我们使用的是

kotlin
var state by mutableStateOf(1)

var state = mutableStateOf(1)

其中使用by的就是利用了Kotlin独特的代理机制,基于Kotlin为我们提供的原生代理机制,我么可以实现不用手动取value的方式来获取状态中的值

渲染过程

使用Room连接本地数据库

Room是Android开发中常用的连接本地数据库的包,其具体是对于原本的SqlLite进行在封装,在2.7.0之后,Room对kMP进行了支持,使得KMP可以使用Android开发的方式来进行跨端开发

首先引入依赖

kotlin
plugins{
	alias(libs.plugins.ksp)  
	alias(libs.plugins.room)
}

//room  
commonMain.dependencies{
	implementation(libs.androidx.room.runtime)  
	implementation(libs.sqlite.bundled)
}

dependencies {  
    debugImplementation(compose.uiTooling)  
    add("kspAndroid", libs.androidx.room.compiler)  
    add("kspCommonMainMetadata", libs.androidx.room.compiler)  
    add("kspDesktop",libs.androidx.room.compiler)  
}

room{  
    schemaDirectory("$projectDir/schemas")  
}

然后在Common下创建两个用于使用ksp生成代码的类

kotlin
//AppDatabase.kt
@Database(entities = [Todo::class], version = 1, exportSchema = true)  
@ConstructedBy(AppDatabaseConstructor::class)  
abstract class AppDatabase : RoomDatabase() {  
    abstract fun todoDao(): TodoDao  
}  
  
// The Room compiler generates the `actual` implementations.  
@Suppress("NO_ACTUAL_FOR_EXPECT")  
expect object AppDatabaseConstructor : RoomDatabaseConstructor<AppDatabase> {  
    override fun initialize(): AppDatabase  
}
kotlin
//CreateDatabase.kt
class CreateDatabase(  
    private val builder:RoomDatabase.Builder<AppDatabase>  
){  
    fun getDateBase():AppDatabase{  
        return builder  
            .fallbackToDestructiveMigration(true)  
            .setDriver(BundledSQLiteDriver())  
            .setQueryCoroutineContext(Dispatchers.IO)  
            .build()  
    }  
}

再在Android包下创建具体的实现

kotlin
//AndroidDatabaseBuilder.kt
fun androidDatabaseBuilder(ctx: Context): RoomDatabase.Builder<AppDatabase> {  
    val appContext = ctx.applicationContext  
    val dbFile = appContext.getDatabasePath("todo.db")  
    return Room.databaseBuilder<AppDatabase>(  
        context = appContext,  
        name = dbFile.absolutePath  
    )  
}

还有desktop端

kotlin
//DesktopDatabaseBuilder.kt
fun desktopDatabaseBuilder(): RoomDatabase.Builder<AppDatabase> {  
    val dbFile = File(System.getProperty("java.io.tmpdir"), "todo.db")  
    return Room.databaseBuilder<AppDatabase>(  
        name = dbFile.absolutePath,  
    )  
}

值得注意的是,目前Room仅支持Desktop,Android,ios三端的本地数据库连接,Web端支持尚且还在孵化中(据说时使用LocalStorage实现)

本站访客数 人次      本站总访问量