推荐一个基于Koin, Ktor Paging等组件的KMM Compose Multiplatform项目

Kotlin Multiplatform Mobile(KMM)已经从一个雄心勃勃的想法发展成为一个稳定而强大的框架,为开发人员提供了在多个平台上无缝共享代码的能力。通过最近的稳定版本里程碑,KMM已成为跨平台开发领域的改变者。

环境设置

带有Kotlin Multiplatform插件的Android Studio

设置Koin和Ktor

  1. 将两个依赖项添加到:shared模块中,我使用gradlelibrary目录作为依赖项。 io.insert-koin:koin-core:3.5.0
  2. 对于Ktor,根据您的API,有多个依赖项各自具有自己的目的。
  3. 由于注入将在平台级别进行,因此我们需要将初始化部分暴露给两个平台。为此,我们将创建一个带有initKoin()方法的Helper类,并从iOS和Android的应用程序类调用此方法。
  4. initKoin() → 我们在这里定义我们稍后需要的所有依赖项。
//shared/src/commonMain/kotlin/di/Koin.kt
fun initKoin() = startKoin {modules(networkModule)
}
private val networkModule = module {single {HttpClient {defaultRequest {url.takeFrom(URLBuilder().takeFrom("https://internshala.com/"))}install(HttpTimeout) {requestTimeoutMillis = 15_000}install(ContentNegotiation) {json(Json {ignoreUnknownKeys = trueprettyPrint = true})}install(Logging) {level = LogLevel.ALLlogger = object : Logger {override fun log(message: String) {println(message)}}}}}
}

2个平台调用此方法:

  1. iOS:我们需要在2个不同的文件中进行更改。(共享iOS文件和特定于平台的文件)
// :shared/src/iosMain/kotlin/Koin.ios.kt
class Koin {fun initKoin() {di.initKoin()}
}
// iosApp/iosApp/iOSApp.swift
import SwiftUI
import shared
@main
struct iOSApp: App {var body: some Scene {WindowGroup {ContentView()}}init() {KoinKt.doInitKoin()}
  1. Android:与iOS不同,对于Android,我们可以直接调用:shared initKoin()方法并初始化Koin。
class App : Application() {override fun onCreate() {super.onCreate()initKoin()}
}

将API响应与Result类进行映射

我们将在Ktor的HttpClient上编写一个小的扩展,用于执行所有API调用并将响应包装在Result(成功/错误)中,并附带适当的消息。

suspend inline fun <reified T> HttpClient.fetch(block: HttpRequestBuilder.() -> Unit
): Result<T> = try {val response = request(block)if (response.status == HttpStatusCode.OK)Result.Success(response.body())elseResult.Error(Throwable("${response.status}: ${response.bodyAsText()}"))
} catch (e: Exception) {Result.Error(e)
}sealed interface Result<out R> {class Success<out R>(val value: R) : Result<R>data object Loading : Result<Nothing>class Error(val throwable: Throwable) : Result<Nothing>
}

设置分页库

在实施Koin和Ktor之后,接下来是分页库。我们将使用来自cashapp的开源库。 由于Paging提供了多种方法来处理错误和API响应,我们将创建一个组合,以处理这种行为。

@Composable
fun <T : Any> PagingListUI(data: LazyPagingItems<T>,content: @Composable (T) -> Unit
) {LazyColumn(modifier = Modifier.fillMaxSize().background(Color.White),horizontalAlignment = Alignment.CenterHorizontally,) {items(data.itemCount) { index ->val item = data[index]item?.let { content(it) }Divider(color = UiColor.background,thickness = 10.dp,modifier = Modifier.border(border = BorderStroke(0.5.dp, Color.LightGray)))}data.loadState.apply {when {refresh is LoadStateNotLoading && data.itemCount < 1 -> {item {Box(modifier = Modifier.fillParentMaxSize(),contentAlignment = Alignment.Center) {Text(text = "No Items",modifier = Modifier.align(Alignment.Center),textAlign = TextAlign.Center)}}}refresh is LoadStateLoading -> {item {Box(modifier = Modifier.fillParentMaxSize(),contentAlignment = Alignment.Center) {CircularProgressIndicator(color = UiColor.primary)}}}append is LoadStateLoading -> {item {CircularProgressIndicator(color = UiColor.primary,modifier = Modifier.fillMaxWidth().padding(16.dp).wrapContentWidth(Alignment.CenterHorizontally))}}refresh is LoadStateError -> {item {ErrorView(message = "No Internet Connection.",onClickRetry = { data.retry() },modifier = Modifier.fillParentMaxSize())}}append is LoadStateError -> {item {ErrorItem(message = "No Internet Connection",onClickRetry = { data.retry() },)}}}}}
}@Composable
private fun ErrorItem(message: String,modifier: Modifier = Modifier,onClickRetry: () -> Unit
) {Row(modifier = modifier.padding(16.dp),horizontalArrangement = Arrangement.SpaceBetween,verticalAlignment = Alignment.CenterVertically) {Text(text = message,maxLines = 1,modifier = Modifier.weight(1f),color = androidx.compose.ui.graphics.Color.Red)OutlinedButton(onClick = onClickRetry) {Text(text = "Try again")}}
}@Composable
private fun ErrorView(message: String,modifier: Modifier = Modifier,onClickRetry: () -> Unit
) {Column(modifier = modifier.padding(16.dp).onPlaced { _ ->},verticalArrangement = Arrangement.Center,horizontalAlignment = Alignment.CenterHorizontally) {Text(text = message,maxLines = 1,modifier = Modifier.align(Alignment.CenterHorizontally),color = androidx.compose.ui.graphics.Color.Red)OutlinedButton(onClick = onClickRetry, modifier = Modifier.fillMaxWidth().padding(16.dp).wrapContentWidth(Alignment.CenterHorizontally)) {Text(text = "Try again")}}
}

设置App和Internship屏幕的UI部分

我们的应用程序入口点 - App.kt

// :shared/src/commonMain/kotlin/App.kt
@Composable
fun App() {MaterialTheme {val screens = Screen.values()var selectedScreen by remember { mutableStateOf(screens.first()) }Scaffold(bottomBar = {BottomNavigation(backgroundColor = Color.White,modifier = Modifier.height(64.dp)) {screens.forEach { screen ->BottomNavigationItem(modifier = Modifier.background(Color.White),selectedContentColor = ui.theme.Color.textOnPrimary,unselectedContentColor = Color.Gray,icon = {Icon(imageVector = getIconForScreen(screen),contentDescription = screen.textValue)},label = { Text(screen.textValue) },selected = screen == selectedScreen,onClick = { selectedScreen = screen },)}}},content = { getScreen(selectedScreen) })}
}@Composable
fun getIconForScreen(screen: Screen): ImageVector {return when (screen) {Screen.INTERNSHIPS -> Icons.Default.AccountBoxScreen.JOBS -> Icons.Default.AddScreen.COURSES -> Icons.Default.Notificationselse -> Icons.Default.Home}
}@Composable
fun getScreen(selectedScreen: Screen) = when (selectedScreen) {Screen.INTERNSHIPS -> InternshipsScreen().content()Screen.JOBS -> JobsScreen()Screen.COURSES -> CoursesScreen()else -> HomeScreen()
}

获取分页数据的实习界面

class InternshipsScreen : KoinComponent {private val viewModel: InternshipViewModel by inject()@Composablefun content() {val result by rememberUpdatedState(viewModel.internships.collectAsLazyPagingItems())return Scaffold(topBar = {TopAppBar(title = { Text("Internships") },elevation = 0.dp,navigationIcon = {IconButton(onClick = { println("Drawer clicked") }) {Icon(imageVector = Icons.Default.Menu, contentDescription = "Menu")}},actions = {IconButton(onClick = { println("Search Internships!") }) {Icon(imageVector = Icons.Default.Search, contentDescription = "Search")}},backgroundColor = Color.White)},drawerContent = { /*Drawer content*/ },content = { PagingListUI(data = result, content = { InternshipCard(it) }) },)}
}

总结:

KMM是一个在多个平台上无缝共享代码的能力的框架。已成为跨平台开发领域的改变者。后续我会自己实战一个KMM项目,包括Ktor的详细讲解,敬请期待。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 指定命令行前后添加echo打印内容

目录 一. 前提条件二. 通过sh脚本进行批量修改三. 通过Excel和文本编辑器进行批量转换四. 实际执行效果 一. 前提条件 ⏹项目中有批量检索文件的需求&#xff0c;如下所示需要同时执行500多个find命令 find ./work -type f -name *.java find ./work -type f -name *.html fi…

Immich自托管服务的本地化部署与随时随地安全便捷在线访问数据

文章目录 前言1.关于Immich2.安装Docker3.本地部署Immich4.Immich体验5.安装cpolar内网穿透6.创建远程链接公网地址7.使用固定公网地址远程访问 前言 小伙伴们&#xff0c;你们好呀&#xff01;今天要给大家揭秘一个超炫的技能——如何把自家电脑变成私人云相册&#xff0c;并…

pytorch 50 大模型导出的onnx模型优化尝试

本博文基于Native-LLM-for-Android项目代码实现,具体做了以下操作: 1、尝试并实现将模型结构与权重零散的onnx模型进行合并,通过该操作实现了模型加载速度提升,大约提升了3倍 2、突破了onnxconverter_common 无法将llm模型导出为fp16的操作,基于该操作后将10g的权重降低到…

Training-free Neural Architecture Search for RNNs and Transformers(预览版本)

摘要 神经架构搜索 (NAS) 允许自动创建新的有效神经网络架构&#xff0c;为手动设计复杂架构的繁琐过程提供了替代方案。然而&#xff0c;传统的 NAS 算法速度慢&#xff0c;需要大量的计算能力。最近的研究调查了图像分类架构的无训练 NAS 指标&#xff0c;大大加快了搜索算…

c++_二叉树的介绍

内存模型 一.内存中有代码区&#xff1b;栈区&#xff1b;数据段 堆区 1、栈区存放了函数所有局部变量和形参&#xff1b; 它的局限在于&#xff1a;局部变量和形参的生存期&#xff1b;即函数返回后对象就会被回收 解决方案是&#xff1a;1&#xff09;使用全局变量 &…

②Modbus TCP转Modbus RTU/ASCII网关同步采集无需编程高速轻松组网

Modbus TCP转Modbus RTU/ASCII网关同步采集无需编程高速轻松组网https://item.taobao.com/item.htm?ftt&id784749793551 网关 MS-A1-5081 MS-A1-5081 网关通过 MODBUS TCP 协议与 Modbus RTU/ASCII 协议的相互转换&#xff0c;可以将 Modbus 串口设备接入 MODBUS TCP 网络…

[网络爬虫] 动态网页抓取 — Selenium 元素定位

&#x1f31f;想系统化学习爬虫技术&#xff1f;看看这个&#xff1a;[数据抓取] Python 网络爬虫 - 学习手册-CSDN博客 在使用 Selenium 时&#xff0c;往往需要先定位到指定元素&#xff0c;然后再执行相应的操作。例如&#xff0c;再向文本输入框中输入文字之前&#xff0c;…

vue实现一个pdf在线预览,pdf选择文本并提取复制文字触发弹窗效果

[TOC] 一、文件预览 1、安装依赖包 这里安装了disjs-dist2.16版本&#xff0c;安装过程中报错缺少worker-loader npm i pdfjs-dist2.16.105 worker-loader3.0.8 2、模板部分 <template><div id"pdf-view"><canvas v-for"page in pdfPages&qu…

Java零基础入门笔记:多线程

前言 本笔记是学习狂神的java教程&#xff0c;建议配合视频&#xff0c;学习体验更佳。 【狂神说Java】Java零基础学习视频通俗易懂_哔哩哔哩_bilibili 第1-2章&#xff1a;Java零基础入门笔记&#xff1a;(1-2)入门&#xff08;简介、基础知识&#xff09;-CSDN博客 第3章…

【VUE2】第三期——样式冲突、组件通信、异步更新、自定义指令、插槽

目录 1 scoped解决样式冲突 2 data写法 3 组件通信 3.1 父子关系 3.1.1 父向子传值 props 3.1.2 子向父传值 $emit 3.2 非父子关系 3.2.1 event bus 事件总线 3.2.2 跨层级共享数据 provide&inject 4 props 4.1 介绍 4.2 props校验完整写法 5 v-model原理 …

蓝桥杯刷题周计划(第二周)

目录 前言题目一题目代码题解分析 题目二题目代码题解分析 题目三题目代码题解分析 题目四题目代码题解分析 题目五题目代码题解分析 题目六题目代码题解分析 题目七题目代码题解分析 题目八题目题解分析 题目九题目代码题解分析 题目十题目代码题解分析 题目十一题目代码题解分…

Redis渐进式遍历数据库

目录 渐进式遍历 数据库 渐进式遍历 keys*可以一次性的把整个redis中所有key都获取到&#xff0c;这个操作是非常危险的&#xff0c;因为可能一下获取到太多的key&#xff0c;阻塞redis服务器。要想很好的获取到所有的key&#xff0c;又不想出现卡死的情况&#xff0c;就可以…

一周学会Flask3 Python Web开发-使用SQLAlchemy动态创建数据库表

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 前面我们定义了模型&#xff0c;我们可以通过sqlalchemy对象提供的create_all()方法来映射和动态创建数据库表。 因为我们用到…

android studio2024最新详解(完全小白)安装-运行第一个程序

前面我用2023最新版本的&#xff0c;死活就卡在引入依赖那里卡了两天&#xff0c;俺的崩溃谁知啊&#xff01;&#xff01; 后面我就换了个思维&#xff0c;看着网上大多的教程都是基于2022或者2020的&#xff0c;我就找了个看起来非常详细的视频&#xff0c;里面的是2020的&am…

laravel中 添加公共/通用 方法/函数

一&#xff0c;现在app 下面创建Common目录&#xff0c;然后在创建Common.php 文件 二&#xff0c;修改composer.json文件 添加这个到autoload 中 "files": ["app/Common/Common.php"]"autoload": {"psr-4": {"App\\": &quo…

c语言笔记 函数参数的等价(上)

这三种写法在 C 语言中是等价的&#xff0c;因为它们都用于声明一个指向二维数组的指针&#xff0c;或者用于声明一个二维数组作为函数参数。它们的等价性源于 C 语言中数组和指针之间的密切关系。让我们逐一分析这三种写法&#xff1a; 在C语言中&#xff0c;当数组作为函数参…

ubuntu局域网部署stable-diffusion-webui记录

需要局域网访问&#xff0c;如下设置&#xff1a; 过程记录查看源码&#xff1a; 查看源码&#xff0c;原来修改参数&#xff1a;--server-name 故启动&#xff1a; ./webui.sh --server-name0.0.0.0 安装下载记录&#xff1a; 快速下载可设置&#xff1a; export HF_ENDPOI…

CTFHub-FastCGI协议/Redis协议

将木马进行base64编码 <?php eval($_GET[cmd]);?> 打开kali虚拟机&#xff0c;使用虚拟机中Gopherus-master工具 Gopherus-master工具安装 git clone https://github.com/tarunkant/Gopherus.git 进入工具目录 cd Gopherus 使用工具 python2 "位置" --expl…

MetaGPT发布的MGX与Devin深度对比

家人们&#xff0c;搞编程的都知道&#xff0c;工具选对了&#xff0c;效率能翻倍&#xff01;今天必须给大伙唠唠MetaGPT发布的MGX编程助手和Devin编程助手 。 先看MGX&#xff0c;简直是编程界的王炸&#xff01;它就像一个超神的虚拟开发团队&#xff0c;一堆智能助手分工明…

Git学习笔记(二)

Git学习笔记&#xff08;二&#xff09; 下载VSCode创建本地仓库推送远程仓库界面功能 使用 VSCode 进行Git仓库的项目管理 这篇文章是我学完使用 命令行终端 管理Git仓库额外学习的 文章主要用于巩固和方便后续复习 下载VSCode 可以看我这篇文章下载VSCode 创建本地仓库 …