每日学习时长评估 - 用KMP打造鸿蒙应用

目录
- 概述
- 功能设计
- Kotlin 实现代码(KMP)
- JavaScript 调用示例
- ArkTS 页面集成与调用
- 数据输入与交互体验
- 编译与自动复制流程
- 总结
概述
本案例在 Kotlin Multiplatform (KMP) 工程中实现了一个 根据每日学习时长评估学习状态工具:
- 输入:每日学习时长数据(单位:分钟),使用空格分隔,例如:
120 90 150 60 180 45 200。 - 输出:
- 基础统计:总学习时长、平均每日学习时长、最长学习时长、最短学习时长
- 深度分析:学习状态评级、学习效率评分、学习坚持度评估
- 个性化建议:根据学习数据给出改进建议和激励语
- 技术路径:Kotlin → Kotlin/JS → JavaScript 模块 → ArkTS 页面调用。
这个案例延续了 KMP 跨端开发的核心理念:
把算法逻辑写在 Kotlin 里,一次实现,多端复用;把交互界面写在 ArkTS 里,专注 UI 和体验。
Kotlin 侧负责解析学习时长数据、计算统计指标、评估学习状态和生成建议文本;ArkTS 侧只需要把输入字符串传给 Kotlin 函数,并把返回结果原样展示出来即可。借助 KMP 的 Kotlin/JS 能力,这个学习评估工具可以在 Node.js、Web 前端以及 OpenHarmony 中复用相同的代码逻辑。
功能设计
输入数据格式
学习时长评估工具采用简单直观的输入格式:
- 使用 空格分隔 每一天的学习时长。
- 每个数字代表该天的学习时长(分钟)。
- 输入示例:
120 90 150 60 180 45 200
这可以理解为最近 7 天的学习情况:
- 第 1 天:学习 120 分钟(2 小时)
- 第 2 天:学习 90 分钟(1.5 小时)
- 第 3 天:学习 150 分钟(2.5 小时)
- 第 4 天:学习 60 分钟(1 小时)
- 第 5 天:学习 180 分钟(3 小时)
- 第 6 天:学习 45 分钟(45 分钟)
- 第 7 天:学习 200 分钟(3.3 小时)
工具会基于这串数据计算出:
- 一共学习了多少分钟(总时长)
- 平均每天学习多少分钟
- 最长的一天学习了多少分钟
- 最短的一天学习了多少分钟
- 学习状态评级(优秀/良好/中等/一般/需要改进)
- 学习效率评分(0-100)
- 学习坚持度评估(连续学习天数、学习稳定性等)
输出信息结构
为了便于在 ArkTS 页面以及终端中直接展示,Kotlin 函数返回的是一段结构化的多行文本,划分为几个分区:
- 标题区:例如"📚 每日学习时长评估分析",一眼看出工具用途。
- 基础统计:总学习时长、平均时长、最长时长、最短时长等指标。
- 学习评估:学习状态等级、效率评分、坚持度评估。
- 详细分析:根据数据给出的具体分析和对比。
- 个性化建议:根据学习数据给出改进建议和激励语。
这样的输出结构使得:
- 在 ArkTS 中可以直接把整段文本绑定到
Text组件,配合monospace字体,阅读体验类似终端报告。 - 如果将来想把结果保存到日志或者后端,直接保存字符串即可。
- 需要更精细的 UI 时,也可以在前端根据分隔符进行拆分,再按块展示。
Kotlin 实现代码(KMP)
核心代码在 src/jsMain/kotlin/App.kt 中,通过 @JsExport 导出。以下是完整的 Kotlin 实现:
@OptIn(ExperimentalJsExport::class)
@JsExport
fun dailyLearningTimeAssessor(inputData: String = "120 90 150 60 180 45 200"): String {
// 输入格式: 一串用空格分隔的数字,代表每天的学习时长(分钟)
val parts = inputData.trim().split(" ").filter { it.isNotEmpty() }
if (parts.isEmpty()) {
return "❌ 错误: 请输入至少一个学习时长数据,例如: 120 90 150 60 180 45 200"
}
val learningTimes = parts.mapNotNull { it.toIntOrNull() }.filter { it >= 0 }
if (learningTimes.isEmpty()) {
return "❌ 错误: 无法解析学习时长数据,请确保输入的都是非负整数"
}
// 基础统计
val totalTime = learningTimes.sum()
val averageTime = totalTime / learningTimes.size
val maxTime = learningTimes.maxOrNull() ?: 0
val minTime = learningTimes.minOrNull() ?: 0
val daysCount = learningTimes.size
// 计算学习状态等级
val statusLevel = when {
averageTime >= 180 -> "优秀"
averageTime >= 120 -> "良好"
averageTime >= 90 -> "中等"
averageTime >= 60 -> "一般"
else -> "需要改进"
}
// 计算学习效率评分(0-100)
val efficiencyScore = when {
averageTime >= 180 -> 95
averageTime >= 150 -> 85
averageTime >= 120 -> 75
averageTime >= 90 -> 65
averageTime >= 60 -> 55
else -> 40
}
// 计算学习稳定性(标准差)
val variance = learningTimes.map { (it - averageTime) * (it - averageTime) }.average()
val stdDev = kotlin.math.sqrt(variance)
val stability = when {
stdDev <= 30 -> "很稳定"
stdDev <= 60 -> "较稳定"
stdDev <= 90 -> "一般"
else -> "波动较大"
}
// 计算连续学习天数
var maxConsecutiveDays = 1
var currentConsecutiveDays = 1
for (i in 1 until learningTimes.size) {
if (learningTimes[i] > 0) {
currentConsecutiveDays++
maxConsecutiveDays = maxOf(maxConsecutiveDays, currentConsecutiveDays)
} else {
currentConsecutiveDays = 1
}
}
// 计算学习坚持度(有效学习天数占比)
val effectiveDays = learningTimes.count { it > 0 }
val persistenceRate = (effectiveDays * 100) / daysCount
// 生成建议
val suggestions = when {
averageTime >= 180 && stability == "很稳定" -> "🌟 学习状态非常优秀!你的学习时长充足且稳定,建议继续保持这个节奏,可以考虑提高学习深度和质量。"
averageTime >= 120 && stability == "很稳定" -> "✨ 学习状态良好!你的学习时长达到了理想水平,学习习惯也很稳定,建议继续坚持。"
averageTime >= 90 -> "👍 学习状态中等。你已经建立了基本的学习习惯,建议逐步增加每天的学习时长,目标是达到 120 分钟以上。"
averageTime >= 60 -> "💪 学习状态一般。你的学习时长还需要提高,建议每天至少学习 90 分钟,可以将学习分成多个时间段进行。"
else -> "⚠️ 学习状态需要改进。你的学习时长较短,建议制定更具体的学习计划,从每天 60 分钟开始逐步增加。"
}
// 生成激励语
val motivation = when {
persistenceRate >= 80 -> "你的学习坚持度很高,这是成功的关键!"
persistenceRate >= 60 -> "你正在建立良好的学习习惯,继续加油!"
else -> "建议增加学习的连贯性,不要中断学习计划。"
}
// 构建输出文本
val result = StringBuilder()
result.append("📚 每日学习时长评估分析\n")
result.append("═".repeat(50)).append("\n\n")
result.append("📊 基础统计\n")
result.append("─".repeat(50)).append("\n")
result.append("总学习时长: ${totalTime} 分钟 (${String.format("%.1f", totalTime / 60.0)} 小时)\n")
result.append("平均每日学习: ${averageTime} 分钟\n")
result.append("最长学习时长: ${maxTime} 分钟\n")
result.append("最短学习时长: ${minTime} 分钟\n")
result.append("统计天数: ${daysCount} 天\n\n")
result.append("🎯 学习评估\n")
result.append("─".repeat(50)).append("\n")
result.append("学习状态等级: ${statusLevel}\n")
result.append("学习效率评分: ${efficiencyScore}/100\n")
result.append("学习稳定性: ${stability}\n")
result.append("学习坚持度: ${persistenceRate}%\n")
result.append("最长连续学习: ${maxConsecutiveDays} 天\n\n")
result.append("💡 详细分析\n")
result.append("─".repeat(50)).append("\n")
result.append("你在过去 ${daysCount} 天内共学习了 ${totalTime} 分钟,平均每天 ${averageTime} 分钟。")
result.append("这表明你的学习投入量处于${statusLevel}水平。\n")
result.append("学习时长的波动程度为${stability},说明你的学习计划执行情况${if (stability == "很稳定") "非常规律" else "需要更加规律"}。\n")
result.append("你有 ${effectiveDays} 天进行了学习,坚持度达到 ${persistenceRate}%,这${if (persistenceRate >= 80) "非常值得肯定" else "还有改进空间"}。\n\n")
result.append("🚀 个性化建议\n")
result.append("─".repeat(50)).append("\n")
result.append("${suggestions}\n")
result.append("${motivation}\n\n")
result.append("📈 学习等级说明\n")
result.append("─".repeat(50)).append("\n")
result.append("• 优秀: 平均每天学习 ≥ 180 分钟\n")
result.append("• 良好: 平均每天学习 120-179 分钟\n")
result.append("• 中等: 平均每天学习 90-119 分钟\n")
result.append("• 一般: 平均每天学习 60-89 分钟\n")
result.append("• 需要改进: 平均每天学习 < 60 分钟\n\n")
result.append("💪 学习建议\n")
result.append("─".repeat(50)).append("\n")
result.append("1. 制定明确的学习目标,建议每天至少学习 120 分钟\n")
result.append("2. 将学习时间分成多个时间段,避免长时间疲劳\n")
result.append("3. 定期评估学习效果,根据需要调整学习计划\n")
result.append("4. 建立学习习惯,保持学习的连贯性和稳定性\n")
result.append("5. 选择适合自己的学习方式,提高学习效率\n")
return result.toString()
}
代码说明
这段 Kotlin 代码实现了完整的学习时长评估功能。让我详细解释关键部分:
数据解析:首先将输入字符串按空格分隔,过滤掉空字符串,然后转换为整数列表。这样可以处理各种格式的输入,包括多个空格的情况。
基础统计:计算总时长、平均时长、最大值和最小值。这些是评估学习状态的基础数据。
状态等级评估:根据平均每日学习时长来判断学习状态。平均时长越长,学习状态等级越高。这个分级标准是根据教育研究中的建议制定的。
效率评分:基于平均学习时长生成 0-100 的评分,用于量化学习效率。
稳定性计算:使用标准差来衡量学习时长的波动程度。标准差越小,说明学习时长越稳定,学习习惯越规律。
连续学习天数:通过遍历数据找出最长的连续学习天数,这反映了用户的学习坚持力。
坚持度评估:计算有效学习天数(学习时长 > 0)占总天数的比例,这反映了用户的学习连贯性。
个性化建议:根据多个维度的数据(平均时长、稳定性、坚持度等)生成相应的建议和激励语。
JavaScript 调用示例
编译后的 JavaScript 代码可以在 Node.js 或浏览器中直接调用。以下是 JavaScript 的使用示例:
// 导入编译后的 Kotlin/JS 模块
const { dailyLearningTimeAssessor } = require('./hellokjs.js');
// 示例 1:基础调用
const result1 = dailyLearningTimeAssessor("120 90 150 60 180 45 200");
console.log("示例 1 - 基础调用:");
console.log(result1);
console.log("\n");
// 示例 2:学习时长较长的情况
const result2 = dailyLearningTimeAssessor("200 210 190 220 200 210 200");
console.log("示例 2 - 优秀学习状态:");
console.log(result2);
console.log("\n");
// 示例 3:学习时长较短的情况
const result3 = dailyLearningTimeAssessor("30 45 20 50 40 35 25");
console.log("示例 3 - 需要改进的学习状态:");
console.log(result3);
console.log("\n");
// 示例 4:学习时长波动较大的情况
const result4 = dailyLearningTimeAssessor("180 60 200 50 190 40 210");
console.log("示例 4 - 学习时长波动较大:");
console.log(result4);
console.log("\n");
// 示例 5:使用默认参数
const result5 = dailyLearningTimeAssessor();
console.log("示例 5 - 使用默认参数:");
console.log(result5);
// 实际应用场景:从用户输入获取数据
function assessUserLearning(userInput) {
try {
const result = dailyLearningTimeAssessor(userInput);
return {
success: true,
data: result
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
// 测试实际应用
const userInput = "120 150 100 180 90 200 110";
const assessment = assessUserLearning(userInput);
if (assessment.success) {
console.log("用户学习评估结果:");
console.log(assessment.data);
} else {
console.log("评估失败:", assessment.error);
}
JavaScript 代码说明
这段 JavaScript 代码展示了如何在 Node.js 环境中调用编译后的 Kotlin 函数。关键点包括:
模块导入:使用 require 导入编译后的 JavaScript 模块,获取导出的 dailyLearningTimeAssessor 函数。
直接调用:可以直接调用函数,传入学习时长数据字符串,函数返回评估结果。
多个示例:展示了不同场景下的调用方式,包括优秀学习状态、需要改进的状态、波动较大的情况等。
错误处理:在实际应用中,应该使用 try-catch 块来处理可能的错误,确保程序的稳定性。
实际应用:assessUserLearning 函数展示了如何在实际应用中集成这个工具,返回结构化的结果对象。
ArkTS 页面集成与调用
在 OpenHarmony 的 ArkTS 页面中集成这个学习评估工具。以下是完整的 ArkTS 实现代码:
import { dailyLearningTimeAssessor } from './hellokjs';
@Entry
@Component
struct LearningAssessmentPage {
@State learningData: string = "120 90 150 60 180 45 200";
@State assessmentResult: string = "";
@State isLoading: boolean = false;
build() {
Column() {
// 顶部栏
Row() {
Text("📚 学习时长评估")
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
}
.width("100%")
.height(60)
.backgroundColor("#1B5E20")
.justifyContent(FlexAlign.Center)
.padding({ top: 10, bottom: 10 })
// 主容器
Scroll() {
Column() {
// 说明文字
Text("请输入每日学习时长数据(单位:分钟,用空格分隔)")
.fontSize(14)
.fontColor("#666666")
.margin({ top: 20, left: 15, right: 15 })
// 输入框
TextInput({
placeholder: "例如: 120 90 150 60 180 45 200",
text: this.learningData
})
.width("90%")
.height(50)
.margin({ top: 15, bottom: 15 })
.padding({ left: 10, right: 10 })
.backgroundColor("#F1F8E9")
.border({ width: 1, color: "#2E7D32" })
.onChange((value: string) => {
this.learningData = value;
})
// 按钮区域
Row() {
Button("🔍 评估学习")
.width("45%")
.height(45)
.backgroundColor("#2E7D32")
.fontColor(Color.White)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.onClick(() => {
this.isLoading = true;
// 模拟异步处理
setTimeout(() => {
this.assessmentResult = dailyLearningTimeAssessor(this.learningData);
this.isLoading = false;
}, 300);
})
Blank()
Button("🔄 重置")
.width("45%")
.height(45)
.backgroundColor("#1565C0")
.fontColor(Color.White)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.onClick(() => {
this.learningData = "120 90 150 60 180 45 200";
this.assessmentResult = "";
this.isLoading = false;
})
}
.width("90%")
.margin({ top: 10, bottom: 20 })
.justifyContent(FlexAlign.SpaceBetween)
// 加载指示器
if (this.isLoading) {
Row() {
LoadingProgress()
.width(40)
.height(40)
.color("#2E7D32")
Text(" 正在评估中...")
.fontSize(14)
.fontColor("#666666")
}
.width("90%")
.height(50)
.margin({ bottom: 15 })
.justifyContent(FlexAlign.Center)
.backgroundColor("#F1F8E9")
.borderRadius(8)
}
// 结果显示区域
if (this.assessmentResult.length > 0) {
Column() {
Text("📊 评估结果")
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor("#1B5E20")
.margin({ bottom: 10 })
Text(this.assessmentResult)
.width("100%")
.fontSize(12)
.fontFamily("monospace")
.fontColor("#333333")
.lineHeight(1.6)
.padding(10)
.backgroundColor("#FAFAFA")
.border({ width: 1, color: "#E0E0E0" })
.borderRadius(8)
}
.width("90%")
.margin({ top: 20, bottom: 30 })
.padding(15)
.backgroundColor("#F1F8E9")
.borderRadius(8)
.border({ width: 1, color: "#2E7D32" })
}
}
.width("100%")
}
.layoutWeight(1)
.backgroundColor("#FFFFFF")
}
.width("100%")
.height("100%")
.backgroundColor("#F5F5F5")
}
}
ArkTS 代码说明
这段 ArkTS 代码实现了完整的用户界面和交互逻辑。关键点包括:
导入函数:从编译后的 JavaScript 模块中导入 dailyLearningTimeAssessor 函数。
状态管理:使用 @State 装饰器管理三个状态:
learningData:用户输入的学习时长数据assessmentResult:评估结果isLoading:加载状态
UI 布局:
- 顶部栏:显示页面标题,使用深绿色背景
- 输入框:允许用户输入学习时长数据
- 按钮区域:包含"评估学习"和"重置"两个按钮
- 加载指示器:在评估过程中显示加载动画
- 结果显示区域:以 monospace 字体显示评估结果
交互逻辑:
- 点击"评估学习"按钮时,调用 Kotlin 函数进行评估,并显示结果
- 点击"重置"按钮时,清空输入和结果
- 使用
setTimeout模拟异步处理,提供更好的用户体验
样式设计:使用绿色主题,与学习相关的主题相符。输入框、按钮和结果显示区域都有相应的样式设置,提供清晰的视觉层次。
数据输入与交互体验
输入数据格式规范
为了确保工具能够正确处理用户输入,用户应该遵循以下规范:
- 数字格式:每个学习时长应该是非负整数,单位为分钟。
- 分隔符:使用空格分隔不同天的学习时长。
- 数据量:至少输入一个数据点,建议输入 7 天以上的数据以获得更准确的评估。
- 范围:学习时长通常在 0-480 分钟之间(0-8 小时)。
示例输入
- 优秀学习状态:
200 210 190 220 200 210 200 - 良好学习状态:
150 140 160 130 170 140 150 - 中等学习状态:
100 90 110 80 120 85 95 - 一般学习状态:
60 50 70 40 80 45 55 - 需要改进:
30 20 40 15 35 25 30
交互流程
- 用户打开应用,看到输入框和默认数据
- 用户可以修改输入框中的数据,或清空后输入自己的数据
- 点击"评估学习"按钮,应用调用 Kotlin 函数进行评估
- 应用显示加载动画,表示正在处理
- 评估完成后,显示详细的评估结果
- 用户可以点击"重置"按钮清空数据,重新开始
编译与自动复制流程
编译步骤
-
编译 Kotlin 代码:
./gradlew build -
生成 JavaScript 文件:
编译过程会自动生成hellokjs.d.ts和hellokjs.js文件。 -
复制到 ArkTS 项目:
使用提供的脚本自动复制生成的文件到 ArkTS 项目的 pages 目录:./build-and-copy.bat
文件结构
编译完成后,项目结构如下:
kmp_openharmony/
├── src/
│ └── jsMain/
│ └── kotlin/
│ └── App.kt (包含 dailyLearningTimeAssessor 函数)
├── build/
│ └── js/
│ └── packages/
│ └── hellokjs/
│ ├── hellokjs.d.ts
│ └── hellokjs.js
└── kmp_ceshiapp/
└── entry/
└── src/
└── main/
└── ets/
└── pages/
├── hellokjs.d.ts (复制后)
├── hellokjs.js (复制后)
└── Index.ets (ArkTS 页面)
总结
这个案例展示了如何使用 Kotlin Multiplatform 技术实现一个跨端的学习评估工具。通过将核心逻辑写在 Kotlin 中,然后编译为 JavaScript,最后在 ArkTS 中调用,我们实现了代码的一次编写、多端复用。
核心优势
- 代码复用:Kotlin 代码可以在 JVM、JavaScript 和其他平台上运行,避免重复开发。
- 类型安全:Kotlin 的类型系统确保了代码的安全性和可维护性。
- 性能优化:Kotlin 编译为 JavaScript 后,性能与手写 JavaScript 相当。
- 易于维护:集中管理业务逻辑,使得维护和更新变得更加容易。
扩展方向
- 数据持久化:将评估结果保存到本地存储或云端。
- 数据可视化:使用图表库展示学习时长的趋势。
- 多用户支持:支持多个用户的学习数据管理。
- 智能推荐:根据学习数据推荐学习计划和资源。
- 社交功能:允许用户分享学习成果和相互鼓励。
通过这个案例,开发者可以学到如何在 KMP 项目中实现复杂的业务逻辑,以及如何在 OpenHarmony 平台上构建高效的跨端应用。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)