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

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

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

环境设置

带有Kotlin Multiplatform插件的Android Studio

https://plugins.jetbrains.com/plugin/14936-kotlin-multiplatform-mobile

Kotlin版本:1.9.10
Gradle版本:8.1.1
用于演示的任何开放API - 在这里,我使用Internshala列表API来填充UI。
注意:使用Internshala的开放列表API,并没有使用不当的做法:)

设置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)}}}}}
}
  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()}
  • 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) }) },)}
}

输出的预览

GitHub

https://github.com/Prashant-123/kmm-ktor-koin
https://github.com/Kamel-Media/Kamel

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

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

相关文章

当「华为还是备选,迪爹还是迪子」时宇宙厂一面原题

写在前面 2021 年还是互联网元年&#xff0c;当时常规的华为 Offer 还是普遍人的备选&#xff0c;如今的迪爹&#xff08;BYD&#xff09;也还是 "来投就给 Offer" 的迪子。 只有字节&#xff0c;当时是公认炙手可热的"宇宙厂"。 作为在 2021 就提前体验了…

青少年心肺复苏培训公益课堂在京开讲

7月30日上午&#xff0c;北京中康联公益基金会联合首都医科大学附属北京佑安医院心血管内科共同举办了“互佑心安——青少年心肺复苏培训公益课堂”。 突发疾病与意外伤害&#xff0c;是生存与健康的最大威胁。据统计&#xff0c;每年全球约有700万人死于心源性猝死&#xff0c…

Oracle Linux 9.3 发布

导读Oracle Linux 9 系列发布了第 3 个版本更新&#xff0c;支持 64 位 Intel 和 AMD (x86_64) 以及 64 位 Arm (aarch64) 平台。与所有的 Oracle Linux 版本一样&#xff0c;此版本与相应 RHEL 版本 100% 应用二进制兼容。 对于 x86_64 和 aarch64 架构&#xff0c;Oracle Li…

跨境电商系统开发:开启全球贸易新纪元

随着全球电子商务的飞速发展&#xff0c;跨境电子商务已经成为了一种日益重要的贸易形式。跨境电商系统开发&#xff0c;为企业提供了全新的商业机遇&#xff0c;打开了全球贸易的新纪元。 跨境电商系统开发&#xff0c;旨在实现不同国家和地区之间的电子商务交易&#xff0c;促…

牛客 算法题 【HJ102 字符统计】 golang实现

题目 HJ102 字符统计 golang代码实现 package mainimport ("bufio""fmt""os""sort" )func main() {// str_arry :make([]string, 0)str_map : make(map[rune]int)result_map : make(map[int][]string)scanner : bufio.NewScanner(os…

大公司为什么喜欢centos系统写爬虫?

CentOS是一个基于Red Hat Enterprise Linux&#xff08;RHEL&#xff09;源代码构建的开源操作系统&#xff0c;它受到大企业喜欢大多数因为他系统的稳定性&#xff0c;安全性以及兼容性等。可以为企业提供更多的商业支持。以我个人为例&#xff0c;公司在做爬虫数据抓取多是采…

[⑥ADRV902x]: 软件系统初始化流程学习

前言 本篇博客主要记录ADRV902x参考软件中对ADRV902x系统的初始化流程&#xff0c;使用API函数来实现transceiver的配置&#xff0c;校准和控制等。官方将整个系统初始化称之为multichip synchronization initialization (MCS) sequence&#xff0c;主要分成PreMcsInit&#x…

jQuery_07 函数的使用

在jQuery中&#xff0c;如何使用函数呢&#xff1f; 1.基本函数 函数(常用的) 其实有很多函数&#xff0c;但是我们只需要掌握常用的函数即可 1.val 操作dom对象的value val() 没有参数 获取dom数组中第一个dom对象的value值 val(value) 有参数 设置dom数组中所有dom对象的…

企业数据建设再思考

近些年企业数据建设进入深水区&#xff0c;近六成受访企业高管表示在未来一到两年会增加数据建设的投入。 数据建设得分最明显的三项指标分别为&#xff1a;开拓数据变现模式、实现数据流与业务流程在各部门间的无缝衔接、搭建基于数据分析的决策体系与管控体系。 因此&#…

webshell之编码免杀

Unicode编码 jsp支持unicode编码&#xff0c;如果杀软不支持unicode查杀的话&#xff0c;基本上都能绕过 注意这里的\uuuu00可以换成\uuuu00uuu...可以跟多个u达到绕过的效果 将代码&#xff08;除page以及标签&#xff09;进行unicode编码&#xff0c;并条件到<%%>标签…

请停止在简历上写: 精通Python, 会害了你

离了个大谱&#xff01; 瑞银暑期实习生都要求精通Python? 你以为能用Python演示“hello world" 就是精通Python了么&#xff1f; too yang too天真 一、不会Python的我们不要 1、瑞士银行 瑞士银行的暑期实习岗位JD中要求应聘者精通编程语言&#xff0c;特别是C或…

SpringBoot中如何优雅地使用重试

1 缘起 项目中使用了第三方的服务&#xff0c; 第三方服务偶尔会出现不稳定、连接不上的情况&#xff0c; 于是&#xff0c;在调用时为了保证服务的相对高可用&#xff0c;添加了超时连接重试&#xff0c; 当连接第三方服务超时时&#xff0c;多重试几次&#xff0c;比如3次&a…